搏击俱乐部~ 还是黑书上的DP啦
题意初看有点像约瑟夫环,n个人逆时针站成一圈,从一个人开始,与其右边的人决斗,输了的就退出圈,问最后n个人中,哪些人有可能留到最后~
问题转化一下,就是将第i个人处,将圈展开,两端都是i,看是否存在一点k,使两端的i可以相互到达;如果可以相互到达,则说明第i个人有可能会赢
dp[i][k] 表示i和k是否可以到达
dp[i][j] 可以到达的条件是:
存在一点k(i<k<j)使dp[i][k] 以及 dp[k][j] 都可到达,并且第i个人和第k个人决斗会赢,或者第j个人和第k个人决斗会赢;
这个地方我纠结了很久,为什么要这样判断啊?
因为只有在第i个人与第k个人决斗会赢时,才能保证第i个人与第j个人的决斗结果可以由本身决斗两人的结果所决定~不然,如果第k个人可以赢第i个人,那么即使第i个人本身可
以赢第j个人,也最后也不能保证第i个人可以赢第j个人。
另外,因为成的是一个环,要将其展开,所以ij要一直更新到2*n。。。
代码:
#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
int dp[150][150];
int a[50][50];
int main(){
int m;
cin>>m;
while(m--){
int n;
cin>>n;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cin>>a[i][j];
}
}
memset(dp,0,sizeof(dp));
for(int i=1;i<=n*2;i++)
dp[i][i+1]=1;
for(int i=2;i<=n*2;i++){
for(int j=1;j<=(2*n-i);j++){
int k=i+j;
for(int g=j+1;g<=k-1;g++){
if((dp[j][g]==1)&&(dp[g][k]==1)){
int temp1=j>n?j-n:j;
int temp2=g>n?g-n:g;
int temp3=k>n?k-n:k;
if((a[temp1][temp2]==1)||a[temp3][temp2]==1){
dp[j][k]=1;
break;
}
}
}
}
}
for(int i=1;i<=n;i++){
cout<<dp[i][i+n]<<endl;
}
cout<<endl;
}
return 0;
}