SP196 MUSKET - Musketeers


题目传送门

题意:

题目描述中讲的比较清楚,就不再赘述了

思路:

区间动归 + 看链为环的思想 :

假设需要判断 x 是否能赢得整场战斗,把环看成链,x 点拆成两个,那么编号为x的人能从中胜出的充分必要条件是他能与自己“相遇”。

这样,在连续几个人的链中,只须考虑头尾两个人能否胜利会师,中间的则不予考虑。

meet[i][j] 记录 i 和 j 能相遇,能则为 $true$,否则为 $false$,则问题转化为了是否能找到一个 k,使得 i 和 k , k 和 j 均能相遇,而 i 或 j 能打败 k。

CODE:

(注释就不加了,理解了思路代码就没什么大问题)


#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
    int x=0,f=1;
    char c=getchar();
    while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
    while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    return x*f;
}
bool e[105][105],meet[205][205],kkk[105];
int t,n,sum;
string s;
signed main(){
    t=read();
    while(t--){
        sum=0;
        n=read();
        for(int i=0;i<n;i++){
            cin>>s;
            for(int j=0;j<n;j++){
                if(s[j]=='1')e[i][j]=1;
                else e[i][j]=0;
            }
        }
    	memset(kkk,0,sizeof(kkk));
		memset(meet,0,sizeof(meet));
        for(int i=0;i<2*n-1;i++)meet[i][i+1]=1;
        for(int k=2;k<=n;k++){
            for(int i=0;i+k<2*n;i++){
                int j=i+k,flag=0;
                for(int q=1;q<j;q++){
                    if(meet[i][q]==1&&meet[q][j]==1&&(e[i%n][q%n]==1||e[j%n][q%n]==1)){
                        flag=1;
                        break;
                    }
                }
                if(flag){
                    meet[i][j]=1;
                    if(k==n)sum++,kkk[i]=1;
                }
            }
        }
        cout<<sum<<endl;
        for(int i=0;i<n;i++){
            if(kkk[i])cout<<i+1<<endl;
        }
    }
    return 0;
}

文章作者: alex_liu
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 alex_liu !
  目录