洛谷 P1879 玉米田(状压DP入门题)
https://www.cnblogs.com/violet-acmer/p/9852294.html
题解:
相关变量解释:
1 int M,N; 2 int plant[maxn][maxn];//草场情况 3 struct Node 4 { 5 int status;//状态 6 int res;//方案 7 Node(int a=0,int b=0):status(a),res(b){} 8 }; 9 vector<Node >dp[maxn];//dp[i][j] : 第i行的j状态能达到的最大方案
根据dp定义,很容易写出状态转移方程:
1 for(int i=1;i <= M;++i) 2 { 3 for(int j=0;j <= maxNum;++j) 4 { 5 int res=Find(j,i-1);//查找与上一次决策没有相邻的草地的决策个数 6 //isSat1() : 判断草地是否合法,即判断不含有相邻草场 7 //isSat2() : 判断当前决策是否有相邻的草地 8 if(isSat1(i,j) && isSat2(j) && res) 9 dp[i].pb(Node(j,res)); 10 } 11 }
AC代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<vector> 4 using namespace std; 5 #define R(x) (1<<x) 6 #define pb(x) push_back(x) 7 const int MOD=1e8; 8 const int maxn=12+10; 9 10 int M,N; 11 int plant[maxn][maxn];//草场情况 12 struct Node 13 { 14 int status;//状态 15 int res;//方案 16 Node(int a=0,int b=0):status(a),res(b){} 17 }; 18 vector<Node >dp[maxn];//dp[i][j] : 第i行的j状态能达到的最大方案 19 bool isSat1(int i,int x)//判断草地是否合法 20 { 21 int index=N; 22 for(int j=1;j <= N;++j) 23 if(plant[i][index--] == 0 && (R(j-1)&x) != 0) 24 return false; 25 return true; 26 } 27 bool isSat2(int x)//判断当前决策是否有相邻的草地 28 { 29 for(int j=2;;++j) 30 { 31 int val=R(j-1)+R(j-2); 32 if(val > x) 33 return true ; 34 if((val&x) == val) 35 return false; 36 } 37 return true; 38 } 39 int Find(int now,int i)//查找与上一次决策没有相邻的草地的决策个数 40 { 41 int res=0; 42 for(int j=0;j < dp[i].size();++j) 43 { 44 Node node=dp[i][j]; 45 int pre=node.status; 46 if((pre&now) == 0) 47 res=res%MOD+node.res; 48 } 49 return res%MOD; 50 } 51 void Solve() 52 { 53 int maxNum=(1<<N)-1; 54 dp[0].pb(Node(0,1)); 55 for(int i=1;i <= M;++i) 56 { 57 for(int j=0;j <= maxNum;++j) 58 { 59 int res=Find(j,i-1); 60 if(isSat1(i,j) && isSat2(j) && res) 61 dp[i].pb(Node(j,res)); 62 } 63 } 64 int res=0; 65 for(int i=0;i < dp[M].size();++i) 66 res=res%MOD+dp[M][i].res; 67 printf("%d\n",res%MOD); 68 } 69 int main() 70 { 71 scanf("%d%d",&M,&N); 72 for(int i=1;i <= M;++i) 73 for(int j=1;j <= N;++j) 74 scanf("%d",plant[i]+j); 75 Solve(); 76 }