华电北风吹
天津大学认知计算与应用重点实验室
日期:2015/8/28
来看POJ3254需要用到状态压缩动态规划题目。
状态压缩的动态规划:实质就是普通的动态规划,只不过每一个状态由一个整数的各个位表示。例如,整数11表示1011这个状态。所以此类表示法仅限于问题排列是01的情况。
POJ3254这个题目需要求农场的种植方案个数问题,每一块农田种或不种用1,0表示即可,因此可以使用状态压缩的动态规划。
对(m*n)的农场建立的动态规划模型为
以农场的行数将动态规划过程划分为m个阶段,每一个阶段有状态 1<<n(2n) 种,这里假设每一行都是可种植的,只需要在动态规划的过程中发现这一块不可种植的时候,将当前状态设置为0即可。每一个状态的决策变量是下一行的种植情况。这样设置状态转移的话,下一行每个状态的值只需要把上一行所有能够转移到此状态的值加起来即可。具体实现参考代码1。
有底向上:
#include<iostream>
#include<ostream>
#include<fstream>
using namespace std;
#define MODULO 100000000
int state[12][4200];
int map[12][12];
int m, n; /* M stands for row and N stands for line. */
int Check(int next)
{
bool last = false;
while (next >0)
{
if (next & 1)
if (last)
return false;
else
last = true;
else
last = false;
next = next >> 1;
}
return true;
}
int main()
{
ifstream in("C:\\Users\\zhengyi\\Desktop\\Google\\input.txt");
cin.rdbuf(in.rdbuf());
int i, j, ans = 0;
cin >> m >> n;
for (i = 0; i < m; i++)
{
for (j = 0; j < 1 << n; j++)
state[i][j] = 0;
}
for (i = 0; i < m; i++)
{
for (j = 0; j < n; j++)
cin >> map[i][j];
}
int tar = 0;
for (i = 0; i < n; i++)
tar += (map[m - 1][i]) << i;
for (i = 0; i < 1 << n; i++)
{
if (Check(i))
{
if (~(tar | ~i) == 0)
{
state[m - 1][i] = 1;
}
}
}
for (i = m - 1; i > 0; i--)
{
for (j = 0; j < 1 << n; j++)
{
if (state[i][j] > 0)
{
for (int k = 0; k < 1 << n; k++)
{
if (Check(k))
if((j&k)==0)
state[i - 1][k] += state[i][j];
}
}
}
tar = 0;
for (j = 0; j < n;j++)
tar += (map[i - 1][j]) << j;
for (j = 0; j < 1 << n; j++)
{
if (~(tar | ~j) != 0)
state[i - 1][j] = 0;
}
}
int result = 0;
for (j = 0; j < 1 << n; j++)
{
result += state[0][j];
}
cout << result << endl;
system("pause");
return 0;
}
带备忘的自顶向下:
#include<iostream>
#include<ostream>
#include<fstream>
using namespace std;
#define MODULO 100000000
int state[12][4200];
int map[12][12];
int m, n; /* M stands for row and N stands for line. */
int Check(int stateSet, int alternative)
{
int i, max = (int)(log(alternative) / log(2));
int c = ~(stateSet | (~alternative));
if (c)
return 0;
else
{
for (i = 0; i < max; i++)
if ((alternative & 1 << i) && (alternative & 1 << (i + 1)))
return 0;
return 1;
}
}
int DPTransfer(int row, int lastRowState)
{
int ans = 0, tar = 0;
if (state[row][lastRowState] >= 0)
return state[row][lastRowState];
else
{
for (int i = 0; i < n; i++)
tar += map[row][i] * (1 << i);
tar &= (~lastRowState);
if (row == m - 1)
{
for (int i = 0; i < 1 << n; i++)
{
if (Check(tar, i))
ans++;
ans %= MODULO;
}
return state[row][lastRowState] = ans % MODULO;
}
else
{
for (int i = 0; i < 1 << n; i++)
{
if (Check(tar, i))
ans += DPTransfer(row + 1, i);
ans %= MODULO;
}
return state[row][lastRowState] = ans % MODULO;
}
}
}
int main()
{
ifstream in("C:\\Users\\zhengyi\\Desktop\\Google\\input.txt");
streambuf *cinbuf = cin.rdbuf(); //save old buf
cin.rdbuf(in.rdbuf()); //redirect std::cin to in.txt!
int result = 0;
cin >> m >> n;
for (int i = 0; i < m; i++)
{
for (int j = 0; j < n; j++)
cin>>map[i][j];
}
for (int i = 0; i < m; i++)
for (int j = 0; j < 1 << n; j++)
state[i][j] = -1;
cout << DPTransfer(0, 0) << endl;
system("pause");
return 0;
}