PKU Online Judge 1033:Kingdom [状态DP]

来源:互联网 发布:成都中科大旗软件 编辑:程序博客网 时间:2024/05/09 21:41

状态DP题,每一列用一个三位的01数字表示,但是直接用原始的01状态去表示发现无法构建出状态dp方程,因为101和111的情况。

为了简化状态,初始的第0列必须有1,那么以后的第0行和第2行的0就不能通过前面列的0连通,只能通过后面列的0连通了。

状态DP,每一列用01表示连通状态,1表示标记为1的格子要连通
因为101和111的连通情况跟其他的状态不一样,为了方便,所以各分成两种情况:
5: 101 该列的1和1靠前面1不连通,需要通过后面列的1连通
6: 101 该列1和1靠前面连通,可以不靠后面的1连通
8: 111 前些列无0,该列后有0
9: 111 前些列有0,该列后无0
这样就能每种情况进行简单的状态转移了,一共有10种状态,那么给这10个状态编号,并且给出各个状态的转换关系。

要注意标记为0的格子也要连通。


f[i][j][k] 表示是否存在第i列的标记状态为j时,编号为1构成的连通块是否有和为k的情况。


状态转换关系表,1表示可以转换,0表示不可以转换。(用excel做的,然后另存为网页,把网页代码粘上来的。)

状态转换关系to




该列的1和1靠前面不连通该列1和1靠前面连通
前些列无0,该列后有0前些列有0,该列后无0



from
000001010011100101101110111111




0001000000000




0011101010001




0101010000000




0111111000001




1001000110101



该列的1和1靠前面不连通1010000010001



该列1和1靠前面连通1011100101001




1101010100101



前些列无0,该列后有01111111101110



前些列有0,该列后无01110000000001



















为了进一步简化状态,初始的第0列必须有1,那么以后的第0行和第2行的0就不能通过前面列的0连通,只能通过后面列的0连通了。                

再贴个图片的表吧。



要注意标记为0的格子也要连通。

/* Kingdom * http://poj.openjudge.cn/practice/1033/ * */#include <cstdio>#include <cstring>#include <algorithm>using namespace std;/* 为了简化状态,初始的第0列必须有1,那么以后的第0行和第2行的0就不能通过前面列的0连通,只能通过后面列的0连通了。 * 状态DP,每一列用01表示连通状态,1表示标记为1的格子要连通 * 因为101和111的连通情况跟其他的状态不一样,为了方便,所以各分成两种情况: * 5: 101 该列的1和1靠前面1不连通,需要通过后面列的1连通 * 6: 101 该列1和1靠前面连通,可以不靠后面的1连通 * 8: 111 前些列无0,该列后有0 * 9: 111 前些列有0,该列后无0 * 这样就能每种情况进行简单的状态转移了,一共有10种状态,那么给这10个状态编号,并且给出各个状态的转换关系,要注意标记为0的格子也要连通 * f[i][j][k]表示是否存在第i列的标记状态为j时,编号为1构成的连通块是否有和为k的情况 * */const int state[10] = {0, 1, 2, 3, 4, 5, 5, 6, 7, 7};const bool trans[10][10] = { // 状态转换关系表`{1,0,0,0,0,0,0,0,0,0}, // 0: 000{1,1,0,1,0,1,0,0,0,1}, // 1: 001{1,0,1,0,0,0,0,0,0,0}, // 2: 010{1,1,1,1,0,0,0,0,0,1}, // 3: 011{1,0,0,0,1,1,0,1,0,1}, // 4: 100{0,0,0,0,0,1,0,0,0,1}, // 5: 101{1,1,0,0,1,0,1,0,0,1}, // 6: 101{1,0,1,0,1,0,0,1,0,1}, // 7: 110{1,1,1,1,1,0,1,1,1,0}, // 8: 111{0,0,0,0,0,0,0,0,0,1}  // 9: 111};int g[3][101];bool f[101][10][1001]; int gs(int c, int s) {s = state[s];int r = 0;for (int i = 0; i < 3; ++i) {if (s & (1<<i)) r += g[i][c];}return r;}int main() {int n, sum;while (EOF != scanf("%d", &n)) {sum = 0;for (int i = 0; i < 3; ++i) {for (int j = 0; j < n; ++j) {scanf("%d", &g[i][j]);sum += g[i][j];}}memset(f, 0, sizeof(f));f[0][4][ gs(0,4) ] = f[0][5][ gs(0,5) ] = f[0][7][ gs(0,7) ] = f[0][8][ gs(0,8) ] = true;for (int i = 0; i < n-1; ++i) {for (int j = 0; j < 10; ++j) {for (int k = 0; k <= sum; ++k) {if (!f[i][j][k]) continue;for (int l = 0; l < 10; ++l) {if (trans[j][l]) f[i+1][l][k+gs(i+1,l)] = true;}}}}int ans = sum;for (int i = 0; i < 10; ++i) {if (i == 2 || i == 5) continue;for (int j = 0; j <= sum; ++j) {if (f[n-1][i][j]) {ans = min(ans, abs(sum - j - j));}}}printf("%d\n", ans);}return 0;}

原创粉丝点击