POJ 1185 解题报告

这道题是状态压缩DP。应该是很有用的方法。


这道题每行可能的状态(每个col放不放炮兵)可以表示为int,即int state。

,同样地形也可以表示为int,某位为1表示该处是hill,即int terrain[N]。

这样状态在某行是否合法可以通过terrain[row] & state判断。如果不为0,说明在hill放兵了,不合法。


这样,总状态数是2 << M,因为每处都可以放或不放兵。但是有些状态可以很轻松除去的,即如果i处放兵,那么无论地形如何,i - 1, i - 2, i + 1, i + 2处都不能放兵。这样需要考虑的状态就只有60种(我没有hard-code这个数字,而用的是vector)。

由于每一行的状态只依赖于前两行,所以处理完一行后,只需保存这行及前一行的状态,就可以接着处理后面的行。


DP其实和枚举差不多,就是对之前两行的所有状态(DP[row - 1][i][j])进行遍历,然后更新当前行的状态(DP[row][k][i]):

DP[row][k][i] = max(DP[row][k][i], DP[row - 1][i][j] + ones[k]);


thestoryofsnow1185Accepted1840K485MSC++
/* 
ID: thestor1 
LANG: C++ 
TASK: poj1185 
*/
#include <iostream>
#include <fstream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <limits>
#include <string>
#include <vector>
#include <list>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <algorithm>
#include <cassert>

using namespace std;

bool hastroop(int state, int col)
{
	return state & (1 << col);
}

bool isvalidcol(int col, int M)
{
	return 0 <= col && col < M;
}

int nof1s(int state)
{
	int cnt = 0;
	while (state)
	{
		state &= state - 1;
		cnt++;
	}
	return cnt;
}

int main()
{
	int N, M;
	scanf("%d%d", &N, &M);
	// if terrain[row][col] is 1, then (row, col) is H (hill)
	// P (plain) otherwise
	std::vector<int> terrain(N, 0);
	for (int row = 0; row < N; ++row)
	{
		for (int col = 0; col < M; ++col)
		{
			char t;
			scanf(" %c", &t);
			if (t == 'H')
			{
				terrain[row] |= 1 << col;
			}
			else
			{
				assert(t == 'P');
			}
		}
	}

	// printf("terrain:\n");
	// for (int row = 0; row < N; ++row)
	// {
	// 	// terrain[row];
	// 	for (int col = 0; col < M; ++col)
	// 	{
	// 		if (terrain[row] & (1 << col))
	// 		{
	// 			printf("H");
	// 		}
	// 		else
	// 		{
	// 			printf("P");
	// 		}
	// 	}
	// 	printf("\n");
	// }

	int power = (int)pow((double)2, M);
	std::vector<int> validstates, ones;
	for (int state = 0; state < power; ++state)
	{
		bool isvalidstate = true;
		for (int col = 0; col < M; ++col)
		{
			// column col has troop
			if (hastroop(state, col))
			{
				// col - 1 also has troop
				if (isvalidcol(col - 1, M) && hastroop(state, col - 1))
				{
					isvalidstate = false;
					break;
				}

				// col - 2 also has troop
				if (isvalidcol(col - 2, M) && hastroop(state, col - 2))
				{
					isvalidstate = false;
					break;
				}

				// col + 1 also has troop
				if (isvalidcol(col + 1, M) && hastroop(state, col + 1))
				{
					isvalidstate = false;
					break;
				}

				// col + 2 also has troop
				if (isvalidcol(col + 2, M) && hastroop(state, col + 2))
				{
					isvalidstate = false;
					break;
				}
			}
		}

		if (isvalidstate)
		{
			validstates.push_back(state);
			ones.push_back(nof1s(state));
		}
	}

	int S = validstates.size();
	std::vector<std::vector<std::vector<int> > > DP(N, std::vector<std::vector<int> > (S, std::vector<int> (S, 0)));
	for (int row = 0; row < N; ++row)
	{
		for (int k = 0; k < S; ++k)
		{
			if (validstates[k] & terrain[row])
			{
				continue;
				// for (int i = 0; i < S; ++i)
				// {
				// 	DP[row][k][i] = 0;
				// }
			}
			else
			{
				for (int i = 0; i < S; ++i)
				{
					if (validstates[k] & validstates[i])
					{
						continue;
					}

					if (row == 0)
					{
						DP[row][k][i] = ones[k];	
						continue;
					}

					for (int j = 0; j < S; ++j)
					{
						if (validstates[k] & validstates[j])
						{
							continue;
						}

						DP[row][k][i] = max(DP[row][k][i], DP[row - 1][i][j] + ones[k]);
					}
				}
			}
		}
	}

	int K = 0;
	for (int i = 0; i < S; ++i)
	{
		for (int j = 0; j < S; ++j)
		{
			K = max(K, DP[N - 1][i][j]);
		}
	}

	printf("%d\n", K);


	return 0;  
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值