Corn Fields POJ - 3254 && 炮兵阵地 POJ - 1185

Posted letlifestop

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Corn Fields POJ - 3254 && 炮兵阵地 POJ - 1185相关的知识,希望对你有一定的参考价值。

第一个题题目链接: POJ - 3254 

第二个题题目链接:POJ - 1185 

第一个题的题目大意:给你一个n*m的01矩阵,然后让你安排奶牛,只有为1的地方能安置奶牛,0的地方不能安置奶牛。当在一个为1的地方安置奶牛的时候,这个奶牛的四周都不能防止奶牛,会起冲突。然后问你一共有多少种安置方案。

具体思路:我们把每一行按照二进制压缩,然后每一次枚举合法的状态,看是否能安置上奶牛,然后枚举当前一行的时候,判断是否冲突就好了。然后最终计算答案的时候累加最后一行为某一个合法状态时的方案数。

AC代码:

技术图片
 1 //dp[i][j]代表当前第i行为j时候的合法数。
 2 #include<iostream>
 3 #include<stdio.h>
 4 #include<cmath>
 5 #include<string>
 6 #include<cstring>
 7 #include<algorithm>
 8 using namespace std;
 9 # define ll long long
10 # define inf 0x3f3f3f3f
11 const int maxn = 5e3+100;
12 const int mod  = 1e9;
13 int dp[20][maxn];
14 int a[20][20];
15 int n,m;
16 bool check(int t1,int t2)
17 {
18     if((((t2<<1)&t2)==0)&&(((t2>>1)&t2)==0))
19     {
20         for(int j=0; j<m; j++){
21             if(((t2&(1<<j))&&a[t1][j])||(!(t2&(1<<j))))
22                 continue;
23             else
24                 return false;
25         }
26         return true;
27     }
28     else
29         return false;
30 }
31 int main()
32 {
33     scanf("%d %d",&n,&m);
34     for(int i=0; i<n; i++)
35     {
36         for(int j=0; j<m; j++)
37         {
38             scanf("%d",&a[i][j]);
39         }
40     }
41     int maxstate=(1<<m)-1;
42     for(int i=0; i<n; i++)
43     {
44         if(i==0)
45         {
46             for(int j=0; j<=maxstate; j++)
47             {
48                 if(check(i,j))
49                     dp[i][j]++;
50             }
51         }
52         else
53         {
54             for(int j=0; j<=maxstate; j++)
55             {
56                 for(int k=0; k<=maxstate; k++)
57                 {
58                     if(check(i,k)&&((j&k)==0))
59                     {
60                         dp[i][k]+=dp[i-1][j];
61                     }
62                 }
63             }
64         }
65     }
66 //    for(int i=0;i<=maxstate;i++){
67 //    cout<<i<<" "<<dp[0][i]<<endl;
68 //    }
69     ll sum=0;
70     for(int i=0; i<=maxstate; i++)
71     {
72         sum=(sum+dp[n-1][i])%mod;
73     }
74     printf("%lld\n",sum);
75     return 0;
76 }
View Code

第二个题题目大意:中文,和上一个题不同的是这个题求的是最大的合法状态。

具体思路:这个题的难度比上一个题的难度增加了一点,上一个题dp[i][j]表示第i行选j这个状态时的合法数。但是这个题需要判断和上两行的关系。所以我们开一个三维数组。

dp[i][j][k]代表第i行选择j状态,第i-1行选k这个状态时的合法数。然后求一个最大值就好了。

具体判断的时候,如果当前的这一行和sto[i],a[i]&sto[j]==sto[j]的时候,就可以了。

注意需要先预处理出合法的状态,否则会爆内存,因为是个三维空间。

AC代码:

技术图片
  1 #include<iostream>
  2 #include<stdio.h>
  3 #include<cmath>
  4 #include<string>
  5 #include<algorithm>
  6 #include<vector>
  7 #include<vector>
  8 using namespace std;
  9 # define ll long long
 10 # define inf 0x3f3f3f3f
 11 const int maxn = 2e2+100;
 12 const int mod  = 1e9;
 13 int dp[100+10][maxn][maxn];
 14 int a[200];
 15 char str[100+100][20];
 16 int sto[maxn],num[maxn];
 17 int n,m;
 18 bool check(int t)
 19 {
 20     if(((t<<1)&t)||((t>>1)&t)||((t<<2)&t)||((t>>2)&t))
 21         return false ;
 22     return true;
 23 }
 24 int cal(int t)
 25 {
 26     int ans=0;
 27     while(t)
 28     {
 29         ans+=(t&1);
 30         t>>=1;
 31     }
 32     return ans;
 33 }
 34 int main()
 35 {
 36     scanf("%d %d",&n,&m);
 37     for(int i=0; i<n; i++)
 38     {
 39         scanf("%s",str[i]);
 40         for(int j=0; j<m; j++)
 41         {
 42             a[i]<<=1;
 43             a[i]|=(str[i][j]==P?1:0);
 44         }
 45     }
 46     int cnt=0;
 47     int maxstate=(1<<m)-1;
 48     for(int i=0; i<=maxstate; i++)
 49     {
 50         if(check(i))
 51         {
 52             sto[++cnt]=i;
 53             num[cnt]=cal(i);
 54         }
 55     }
 56     int maxx=0;
 57     for(int i=0; i<n; i++)
 58     {
 59         if(i==0)
 60         {
 61             for(int j=1; j<=cnt; j++)
 62             {
 63                 if((a[i]&sto[j])!=sto[j])continue;
 64                     dp[i][j][0]=max(dp[i][j][0],num[j]);
 65                     maxx=max(maxx,dp[i][j][0]);
 66             }
 67         }
 68         else if(i==1)
 69         {
 70             for(int j=1; j<=cnt; j++)
 71             {
 72                 if((sto[j]&a[i])!=sto[j])continue;
 73                 for(int k=1; k<=cnt; k++)
 74                 {
 75                     if((sto[k]&a[i-1])!=sto[k])continue;
 76                     if((sto[j]&sto[k])!=0)continue;
 77                     dp[i][j][k]=max(dp[i][j][k],dp[i-1][k][0]+num[j]);
 78                     maxx=max(maxx,dp[i][j][k]);
 79                 }
 80             }
 81         }
 82         else
 83         {
 84             for(int j=1; j<=cnt; j++)
 85             {
 86                 if((sto[j]&a[i])!=sto[j])
 87                     continue;
 88                 for(int k=1; k<=cnt; k++)
 89                 {
 90                     if((sto[k]&a[i-1])!=sto[k]||(sto[k]&sto[j])!=0)
 91                         continue;
 92                     for(int L=1; L<=cnt; L++)
 93                     {
 94                         if((sto[L]&a[i-2])!=sto[L])
 95                             continue;
 96                         if((sto[j]&sto[L])!=0||(sto[k]&sto[L])!=0)
 97                             continue;
 98                         dp[i][j][k]=max(dp[i][j][k],dp[i-1][k][L]+num[j]);
 99                         maxx=max(maxx,dp[i][j][k]);
100                     }
101                 }
102             }
103         }
104     }
105     printf("%d\n",maxx);
106 }
View Code

 

以上是关于Corn Fields POJ - 3254 && 炮兵阵地 POJ - 1185的主要内容,如果未能解决你的问题,请参考以下文章

POJ3254Corn Fields

POJ 3254 Corn Fields(状压DP)

poj3254 Corn Fields

POJ 3254 Corn Fields(状压dp)

POJ 3254 - Corn Fields - [状压DP水题]

poj-3254 Corn Fields(状压dp)