POJ1185 炮兵部队问题:

在平原上才能放置炮兵,每个炮兵的上下左右2格之内都不能出现别的炮兵

可以考虑在当前行放置炮兵它的右侧和下侧绝对不会出现炮兵即可,左侧和上侧就能省去考虑

明显的状态压缩dp题,但是题目所给的有10列,因为每行都与前两行的状态有关,那么也就是根据当前,上一行,上上行3行状态来修改

dp[i][v][u]的状态方程

因为这里直接3重循环会爆,但是我们很容易发现,可以预处理一些关于行的合法状态,那么状态数就少了很多,接下来考虑的时候就省去了行上的相关影响

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 using namespace std;
 5 
 6 const int N = 1<<11;
 7 int dp[105][100][100] , state[N];
 8 int can[100] , tot[100] , cnt;
 9 char str[15];
10 
11 void init_dfs(int k , int u , int v)
12 {
13     if(k<0){
14         tot[cnt] = v;
15         can[cnt++] = u;
16         return;
17     }
18     init_dfs(k-3 , u|(1<<k) , v+1);
19     init_dfs(k-1 , u , v);
20 }
21 
22 int main()
23 {
24  //   freopen("a.in" , "r" , stdin);
25     int n,m;
26     while(scanf("%d%d" , &n , &m) != EOF)
27     {
28         for(int i=1 ; i<=n ; i++){
29             scanf("%s" , str);
30             state[i] = 0;
31             for(int j=0 ; j<(int)strlen(str) ; j++){
32                 state[i] <<= 1;
33                 if(str[j] == 'P') state[i]+=1;
34             }
35            // cout<<"state: "<<state[i]<<endl;
36         }
37         //找到所有符合的状态,减少状态数
38         cnt = 0;
39         init_dfs(m-1 , 0 , 0);
40      //   cout<<cnt<<endl;
41 
42         if(n==1){
43             int maxn=0;
44             for(int i=0 ; i<cnt ; i++)
45                 if((state[1]&can[i]) == can[i])
46                     maxn = max(maxn , tot[i]);
47             printf("%d\n" , maxn);
48             continue;
49         }
50 
51         memset(dp , 0 , sizeof(dp));
52         for(int i=0 ; i<cnt ; i++){
53             for(int j=0 ; j<cnt ; j++){
54                 int t1 = state[1]&can[i] , t2 = state[2]&can[j];
55                 if(t1 == can[i] && t2 == can[j] && !(can[i]&can[j]))
56                 {
57                    // cout<<"test: "<<i<<" "<<j<<" "<<can[i]<<" "<<can[j]<<" tot: "<<tot[i]<<" "<<tot[j]<<endl;
58                     dp[2][i][j] = tot[i] + tot[j];
59                 }
60             }
61         }
62         state[0] = (1<<m)-1;
63         for(int i=3 ; i<=n ; i++){
64             for(int u=0 ; u<cnt ; u++){
65                 if((state[i]&can[u]) < can[u]) continue;
66                 for(int v=0 ; v<cnt ; v++){
67                     if((state[i-1]&can[v]) < can[v]) continue;
68                     if((can[v]&can[u])) continue;
69                     for(int w=0 ; w<cnt ; w++){
70                         if((state[i-2]&can[w]) < can[w]) continue;
71                         if((can[v]&can[w]) || (can[u]&can[w])) continue;
72                         dp[i][v][u] = max(dp[i][v][u] , dp[i-1][w][v] + tot[u]);
73                     }
74                 }
75             }
76         }
77         int maxn = 0;
78         for(int i=0 ; i<cnt ; i++){
79             for(int j=0 ; j<cnt ; j++)
80                 maxn = max(maxn , dp[n][i][j]);
81         }
82         printf("%d\n" , maxn);
83     }
84     return 0;
85 }
View Code

POJ 2411 木板拼接问题:

在n*m的方格中,放1*2或者2*1的木板,问有多少摆放的种数

题目会超int,答案输出用long long

这里用dp[i][u]表示到达第 i 行时状态为 u ,且前面行的格子已经全部被木板填充完全,所能达到的方法种数

每次对于当前行的状态只跟上一行有关,dp[i+1][u] += dp[i][v] 

通过v可以拼出 u 的情况,我们总是在u,v上放2*1的板,或只在u 上放1*2的板,不能在v上放1*2的板,这样会与原来 v 作为当前行时在其上放1*2的情况重复

且必须保证全部放完后,上一行v 全部填充满(v == (1<<m)-1) ,才更新数据

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 using namespace std;
 5 #define ll long long
 6 ll dp[15][10005];
 7 
 8 void dfs(int i , int u , int v , int full , int k , ll val)
 9 {
10     if(k<0){
11         if(v == full) dp[i][u] += val;
12         return ;
13     }
14     if(k>=1 && !(u&(3<<(k-1)))) dfs(i , u|(3<<(k-1)) , v , full ,k-2 , val);
15     if(!(u&(1<<k)) && !(v&(1<<k))) dfs(i , u|(1<<k) , v|(1<<k) , full , k-1 , val);
16     if(!(v&(1<<k))) return ;
17     dfs(i , u , v , full , k-1 , val);
18 }
19 
20 int main()
21 {
22   //  freopen("a.in" , "r" , stdin);
23     int n,m;
24     while(scanf("%d%d" , &n , &m) ,n||m)
25     {
26         memset(dp , 0 , sizeof(dp));
27         dfs(1 , 0 , (1<<m)-1 , (1<<m)-1 , m-1 , 1);
28         for(int i=2 ; i<=n ; i++){
29             for(int j=0 ; j<(1<<m) ; j++){
30                 if(dp[i-1][j]) dfs(i , 0 , j , (1<<m)-1 , m-1 , dp[i-1][j]);
31             }
32         }
33         printf("%I64d\n" , dp[n][(1<<m)-1]);
34     }
35     return 0;
36 }
View Code

HDU2280 填充问题:

将所给的积木装入平面上,保证最后剩余的格数能够尽可能的少

因为积木最大也就两行,所以每次当前行只受上一行的影响

dp[i][u]记录当前 i 行 状态 为 u 时剩余的格子的最小数目

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <iostream>
  4 using namespace std;
  5 const int INF = 0x3f3f3f3f;
  6 const int N = 1005;
  7 
  8 int dp[N][40] , state[N];
  9 char str[8];
 10 
 11 int cnt_0(int u)
 12 {
 13     int ans = 5;
 14     while(u){
 15         if(u&1) ans--;
 16         u>>=1;
 17     }
 18     return ans;
 19 }
 20 
 21 void dfs1(int i , int u , int cnt , int k) //k为当前的长度,从0开始
 22 {
 23     if(k < 0){
 24         dp[i][u] = min(dp[i][u] , cnt);
 25         return ;
 26     }
 27     if(k >= 1 && !(u&(3<<(k-1)))){
 28         int v = u|(3<<(k-1));
 29         dfs1(i , v , cnt-2 , k-2);
 30     }
 31     dfs1(i,u,cnt,k-1);
 32 }
 33 //u为当前行状态,v为上一行状态,cnt为当前行0的数量
 34 void dfs2(int i , int u , int v , int cnt , int k)
 35 {
 36     if(k < 0){
 37         dp[i][u] = min(dp[i][u] , cnt);
 38         return ;
 39     }
 40     if(k>=1){
 41         if(!(u&(3<<(k-1)))){
 42             int p = u|(3<<(k-1));
 43             dfs2(i , p , v , cnt-2 , k-2);
 44         }
 45         if(!(u&(3<<(k-1))) && !(v&(1<<(k-1)))){
 46             int p = u|(3<<(k-1));
 47             int q = v|(1<<(k-1));
 48             dfs2(i , p , q , cnt-3 , k-2);
 49         }
 50         if(!(u&(3<<(k-1))) && !(v&(1<<k))){
 51             int p = u|(3<<(k-1));
 52             int q = v|(1<<k);
 53             dfs2(i , p , q , cnt-3 , k-2);
 54         }
 55         if(!(v&(3<<(k-1))) && !(u&(1<<(k-1)))){
 56             int p = u|(1<<(k-1));
 57             int q = v|3<<(k-1);
 58             dfs2(i , p , q , cnt-3 , k-2);
 59         }
 60         if(!(v&(3<<(k-1))) && !(u&(1<<k))){
 61             int p = u|(1<<k);
 62             int q = v|(3<<(k-1));
 63             dfs2(i , p , q , cnt-3 , k-1);
 64         }
 65     }
 66     if(!(u&(1<<k)) && !(v&(1<<k))){
 67         int p = u|(1<<k);
 68         int q = v|(1<<k);
 69         dfs2(i , p , q , cnt-2 , k-1);
 70     }
 71     dfs2(i , u , v , cnt , k-1);
 72 }
 73 
 74 int main()
 75 {
 76   //  freopen("a.in" , "r" , stdin);
 77     int n , m;
 78     while(scanf("%d%d" , &n , &m) != EOF)
 79     {
 80         for(int i=1 ; i<=n ; i++){
 81             state[i] = 0;
 82             scanf("%s" , str);
 83             for(int j=0 ; j<5 ; j++){
 84                 int t = str[j]-'0';
 85                 state[i] = state[i]*2+t;
 86             }
 87         }
 88 
 89         memset(dp , 0x3f , sizeof(dp));
 90         dp[1][state[1]] = cnt_0(state[1]);
 91         dfs1(1 , state[1] , dp[1][state[1]] , 4);
 92 
 93         for(int i=2 ; i<=n ; i++){
 94             for(int p=0 ; p<32 ; p++){
 95                 if(dp[i-1][p] <INF){
 96                   //  cout<<"state : i: "<<i<<" p: "<<p<<" "<<dp[i-1][p]+cnt_0(state[i])<<endl;
 97                     dfs2(i , state[i] , p , dp[i-1][p]+cnt_0(state[i]) , 4);
 98                 }
 99             }
100         }
101         int minn = INF;
102         for(int i=0 ; i<32 ; i++)
103             minn = min(minn , dp[n][i]);
104      //   cout<<minn<<endl;
105         printf("%s\n" , minn<=m?"YES":"NO");
106     }
107     return 0;
108 }
View Code

 HDU 2442 方格填充

通过所给的5种形式的木块无覆盖填充n*m的方格,问最多有多少方格被填充

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 
 5 using namespace std;
 6 
 7 const int N = 1<<6;
 8 int dp[105][N][N];
 9 
10 void dfs(int i , int w , int v , int u , int val , int k)
11 {
12     if(k<0){
13         dp[i][v][u] = max(dp[i][v][u] , val);
14         return;
15     }
16     if(k>=2){
17         if(!(w&(1<<(k-1))) && !(v&(7<<(k-2))) && !(u&(1<<(k-1))))
18             dfs(i , w|(1<<(k-1)) , v|(7<<(k-2)) , u|(1<<(k-1)) , val+5 , k-3);
19         if(!(v&(7<<(k-2))) && !(u&(1<<(k-1))))
20             dfs(i , w , v|(7<<(k-2)) , u|(1<<(k-1)) , val+4 , k-3);
21         if(!(v&(7<<(k-2))) && !(u&(1<<k)))
22             dfs(i , w , v|(7<<(k-2)) , u|(1<<k) , val+4 , k-3);
23     }
24     if(k>=1){
25         if(!(w&(1<<k)) && !(v&(3<<(k-1))) && !(u&(1<<k)))
26             dfs(i , w|(1<<k) , v|(3<<(k-1)) , u|(1<<k) , val+4 , k-2);
27         if(!(w&(3<<(k-1))) && !(v&(1<<k)) && !(u&(1<<k)))
28             dfs(i , w|(3<<(k-1)) , v|(1<<k) , u|(1<<k) , val+4 , k-1);
29     }
30     dfs(i , w , v , u , val , k-1);
31 }
32 
33 int main()
34 {
35   //  freopen("a.in" , "r" , stdin);
36     int n,m;
37     while(scanf("%d%d" , &n , &m) == 2)
38     {
39         memset(dp , -1 , sizeof(dp));
40         dp[1][(1<<m)-1][0] = 0;
41         for(int i=2 ; i<=n ; i++){
42             for(int w=0 ; w<(1<<m) ; w++){
43                 for(int v=0 ; v<(1<<m) ; v++){
44                     if(dp[i-1][w][v]>=0) dfs(i , w , v , 0 , dp[i-1][w][v] , m-1);
45                 }
46             }
47         }
48         int ans = 0;
49         for(int v=0 ; v<(1<<m) ; v++)
50             for(int u=0 ; u<(1<<m) ; u++)
51                 ans = max(ans , dp[n][v][u]);
52         printf("%d\n" , ans);
53     }
54     return 0;
55 }
View Code

 

 posted on 2015-01-26 14:21  Love风吟  阅读(237)  评论(0编辑  收藏  举报