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 }
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 }
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 }
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 }