Fight Club

来源:互联网 发布:51单片机串口程序 编辑:程序博客网 时间:2024/04/28 05:40

搏击俱乐部~  还是黑书上的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; }


 

原创粉丝点击