C17K:Lying Island
题意:
有n个人,每个人可能会说:
- 第x个人是好人/坏人
- 如果第x个人是好人/坏人,则第y个人是好人/坏人
思路:
状压dp,首先每个人所说的人只能是他前面10个人,所以对于第i个人记录下,他前面十个人的情况。
对于第i个人,如果他说的话一个状态不冲突,那么i可以由这个状态转移。
注意:对于“如果第x个人是好人,那么第y个人是坏人 “,那么x是好人,y是好人是不满足的。但是除了x是好人y是坏人这种情况满足,x是坏人,也是满足的。(一定要学好语文!)
代码
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<iostream> 5 #include<cmath> 6 7 using namespace std; 8 9 int dp[5010][1050]; 10 char str[50]; 11 int k; 12 13 void work1(int i,int x,int z) { 14 int t = (1 << k); 15 for (int j=0; j<t; ++j) { 16 if (((j>>(x-i+k))&1)==z) dp[i][(j+t)>>1] = max(dp[i][(j+t)>>1],dp[i-1][j]+1); 17 dp[i][j>>1] = max(dp[i][j>>1],dp[i-1][j]); 18 } 19 } 20 void work2(int i,int x,int y,int z1,int z2) { 21 int t = (1 << k); 22 for (int j=0; j<t; ++j) { 23 int t1 = ((j>>(x-i+k))&1) == z1,t2 = ((j>>(y-i+k))&1) != z2; 24 if (!(t1&&t2)) dp[i][(j+t)>>1] = max(dp[i][(j+t)>>1],dp[i-1][j]+1); 25 dp[i][j>>1] = max(dp[i][j>>1],dp[i-1][j]); 26 } 27 } 28 int main() { 29 int T,n,x,y,z; 30 scanf("%d",&T); 31 while (T--) { 32 scanf("%d%d",&n,&k); 33 memset(dp,-1,sizeof(dp)); 34 for (int j=0,t=(1<<(k-1)); j<t; ++j) dp[1][j] = 0; 35 for (int j=(1<<(k-1)),t=(1<<k); j<t; ++j) dp[1][j] = 1; 36 37 for (int i=2; i<=n; ++i) { 38 scanf("%s%s%s%d",str,str,str,&x); 39 if (str[0]=='P') { 40 scanf("%s%s%s",str,str,str); 41 if (str[0]=='g') z = 1; 42 else z = 0; 43 scanf("%s",str); 44 work1(i,x,z); 45 } 46 else { 47 scanf("%s%d%s%s%s",str,&x,str,str,str); 48 if (str[0]=='g') z = 1; 49 else z = 0; 50 scanf("%s%s%d%s%s%s",str,str,&y,str,str,str); 51 work2(i,x,y,z,str[0]=='g'); 52 scanf("%s",str); 53 } 54 } 55 int ans = 0; 56 for (int i=0,t=(1<<k); i<t; ++i) ans = max(ans,dp[n][i]); 57 printf("%d\n",ans); 58 } 59 return 0; 60 }