SPOJ 196 动态规划
题意:黑书P117 决斗
分析:假设需要判断x是否能赢得整场战斗,把环看成链,x点拆成两个,那么编号为x的人能从中胜出的充分必要条件是他能与自己“相遇”。
这样,在连续几个人的链中,只须考虑头尾两个人能否胜利会师,中间的则不予考虑。
设meet[i][j]记录i和j能相遇,能则为true,否则为false,则问题转化为了是否能找到一个k,使得i 和 k, k和j均能相遇,而 i或j能打败k。
const int M = 202; int n; int a[M][M], meet[M][M]; void readData(){ cin>>n; char c; FOE(i, 1, n){ cin.get(c); FOE(j, 1, n){ cin.get(c); a[i][j]=c-'0'; } } memset(meet,0,sizeof meet); FOR(i, 1, n<<1) meet[i][i+1]=1; } void d(int i,int j){ if(meet[i][j]) return; FOR(k, i+1, j) { int ii=(i-1)%n+1, jj=(j-1)%n+1, kk=(k-1)%n+1; if(a[ii][kk] || a[jj][kk]) { d(i,k); d(k,j); if(meet[i][k]==1&&meet[k][j]==1) { meet[i][j]=1; return; } } } meet[i][j]=-1; } void solve(){ int cnt=0; FOE(i, 1, n) { d(i,i+n); if(meet[i][i+n]==1) cnt++; } cout<<cnt<<endl; FOE(i, 1, n) if(meet[i][i+n]==1) cout<<i<<endl; } int main(){ int t; cin>>t; while(t--) { readData(); solve(); } return 0; }