题目地址:http://hihocoder.com/problemset/problem/1044
算法思路:此题可以看做是铺地砖的变形,没有明显的行数和状态,但是我们可以自己将其中的行和状态给扣出来。其中第一行就是N个数的中前(0,1,2…M-1), 第二行就是(2,3..M)…一直到最后一行为(N-M…N)。每一行的状态个数即为2^M-1(即这M个位置要么填写1,要么填写0)。此时可用F[i][j]表示第i行状态为j时的垃圾最大值。最终的结果就是第N-M行所对应的状态中的最大值。
上一遍blog对状态压缩讲的比较详细,可以参看 http://blog.csdn.net/lu597203933/article/details/44137277
代码:
#include <iostream> #include <memory.h> #include <time.h> using namespace std; #define NMax 1000 #define MMax 1 << 10 long long F[NMax][MMax]; bool testCompatibility(int j, int M, int Q) // 判断该状态j是否是连续的M中有大于Q个1 { int i = 0; int count = 0; while(i < M) { if(j & (1 << i)) { count ++; } i++; } if(count > Q)return false; else return true; } long long getFirstLine(int j, int M, int *W) // 得到“第一行”的垃圾总量 { int i = 0; long long rubbish = 0; while(i < M) { if(j & (1 << i)) { rubbish += W[M-1-i]; } i++; } return rubbish; } bool testRemaining(int j, int k, int M) // 判断j的最高M-1位是否等于k的低M-1位 即判断状态j与上一状态k是否兼容 { k = k & ~(1<<(M-1)); // 将k的第M-1位置0 k = k << 1; k = k | (j & 1); if (k == j) return true; else return false; } int main() { int N, M, Q; while(cin >> N >> M >> Q){ int W[NMax]; int sta[NMax]; int tt = 0; int allStates = 1 << M; int i, j; for(i = 0; i < N; i++) cin >> W[i]; memset(F, 0 , sizeof(F)); long long maxRubbish = 0; for(j = 0; j < allStates; j++) { if(testCompatibility(j, M, Q)) { sta[tt++] = j; // 将可用的状态保存到一个数组sta中 如果没有这个sta 则需要遍历所有的状态 } } for(int j = 0; j < tt; j++) F[0][j] = getFirstLine(sta[j], M, W); // 得到前m个单元的状态 for(i = 1; i <= N - M; i++) { for(j = 0; j < tt; j++) { for(int k = 0; k < tt; k++) { int aa = sta[k] & ~(1<<(M-1)); // 将k的第M-1位置0 aa = aa<< 1; aa = aa | (sta[j] & 1); //if(testRemaining(sta[j], sta[k], M)) // 在循环中尽量不要用函数,否则调用开销会很大 if(aa == sta[j]) { F[i][j] = max(F[i-1][k],F[i][j]); } } if(((sta[j] & 1) == 1)) { F[i][j] += W[i+M-1]; } } } for(int j = 0; j < tt; j++) maxRubbish = max(maxRubbish, F[N-M][j]); cout << maxRubbish << endl; } return 0; } /* input: 5 2 1 36 9 80 69 85 10 8 3 38 98 97 87 76 67 56 65 53 76 output: 201 362 */
但是此题我代码提交的时候TLE,显示超时了,但是我自己将所用时间输出来了了,比网上给的代码http://hhfgeg.name/?id=158还有少,但始终TLE,不知道为什么,有知道的可以评论。谢谢!
下面总结一般状态压缩的解法步骤
1:将题目转换成状态压缩的问题,F[i][j]表示第i行状态为j时的最大方案数。
2:初始化,初始化第0行各状态所对应的方案数(垃圾量)
3:通过判断第i行的状态j是否与上一行的各状态的兼容性去求F[i][j]
4:通过题目求出最终的结果