【状压DP】OpenJ_POJ - C17K Lying Island

https://vjudge.net/contest/171652#problem/K

【题意】

  • 小岛上有n个人,有些是好人(一定是真话),有些是坏人(可能是真话也可能是假话),现在要判断最多有多少好人
  • 每个人说话有四种形式:
  • 1. Person i: Person x is a good guy. 
  • 2. Person i: Person x is a bad guy. 
  • 3. Person i: If person x is a good guy, person y is a good guy. 
  • 4. Person i: If person x is a bad guy, person y is a bad guy. 
  • 从2到n依次考察n-1个人
  • 对于第i个人,他知道的信息只有从max(i-k,1)到i-1
  • 0 <= N <= 5000,1 <= K <= 10

【思路】

  • 对于第i个人,他只知道max(i-k,1)到i-1个人的信息,k最多是10。用1表示好人,0表示坏人,max(i-k,1)到i-1个人的信息可以状压保存,高位是编号大的人
  • dp[i][j]表示考察到第i个人时,状态为j(最高位为i的状态)时好人最多是多少个
  • 初始化:对于第一个人,可能是好人也可能是坏人,所以第k位为1时,第一个人是好人,dp为1;第k位为0时,dp为0
  • 状态转移:如果第i个人说的话与max(i-k,1)到i-1本身的信息相符,说第i个人可能是好人,状态转移为,右移并且最高位置1,好人数增加一个;不管相符还是不符,第i个都可能是坏人,状态转移为,右移一位最高位置0,好人数不增加
  • 注意第四种说话方式时,只有if 符合而then不符合,可以确定当前人一定不是好人,否则都有可能是好人

【Accepted】

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<string>
 5 #include<algorithm>
 6 #include<cmath>
 7 
 8 using namespace std;
 9 const int maxn=5e3+2;
10 int dp[maxn][1030];
11 int n,k;
12 int main()
13 {
14     int T;
15     scanf("%d",&T);
16     while(T--)
17     {
18         memset(dp,-1,sizeof(dp));
19         scanf("%d%d",&n,&k);
20         for(int i=0,mx=(1<<(k-1));i<mx;i++)
21         {
22             dp[1][i]=0;
23         }
24         for(int i=(1<<(k-1)),mx=(1<<k);i<mx;i++)
25         {
26             dp[1][i]=1;
27         }
28         for(int i=2;i<=n;i++)
29         {
30             char str[10];
31             int x,y,dx,dy;
32             scanf("%s%d%s%s",str,&x,str,str);
33             if(str[0]=='P')
34             {
35                 scanf("%d%s%s%s",&x,str,str,str);
36                 if(str[0]=='g') dx=1;
37                 else dx=0;
38                 for(int j=0,mx=(1<<k);j<mx;j++)
39                 {
40                     if(((j>>(x-i+k))&1)==dx)
41                     {
42                         dp[i][(j+mx)>>1]=max(dp[i][(j+mx)>>1],dp[i-1][j]+1);
43                     } 
44                     dp[i][j>>1]=max(dp[i][j>>1],dp[i-1][j]);
45                 }
46                 scanf("%s",str);
47             }
48             else
49             {
50                 scanf("%s%d%s%s%s",str,&x,str,str,str);
51                 if(str[0]=='g') dx=1;
52                 else dx=0;
53                 scanf("%s%s%d%s%s%s",str,str,&y,str,str,str);
54                 if(str[0]=='g') dy=1;
55                 else dy=0;
56                 scanf("%s",str);
57                 for(int j=0,mx=(1<<k);j<mx;j++)
58                 {
59                     if(!((((j>>(x-i+k))&1)==dx)&&(((j>>(y-i+k))&1)!=dy)))
60                     {
61                         dp[i][(j+mx)>>1]=max(dp[i][(j+mx)>>1],dp[i-1][j]+1);
62                     }
63                     dp[i][j>>1]=max(dp[i][j>>1],dp[i-1][j]);
64                 }
65             }
66         }
67         int ans=0;
68         for(int i=0,mx=(1<<k);i<mx;i++)
69         {
70             ans=max(ans,dp[n][i]);
71         }
72         printf("%d\n",ans);
73     }
74     return 0;
75  } 
状压DP

 

posted @ 2017-07-22 20:21  shulin15  阅读(339)  评论(0编辑  收藏  举报