HDU ACM 4539 郑厂长系列故事——排兵布阵->状态压缩DP

分析:dp[i][j][k]表示第i行状态为j,i-1行状态为k时的客房士兵的最大值。

曼哈顿距离是指:|x1-x2|+|y1-y2|。

当前行不仅与前一行有关,还和前两行有关,所以开数组的时候还要记录前两行的状态,所以开设三维数组。

每行可压缩为二进制集合,状态dp[i][j][k]为第i行为集合j,第i-1行为集合k,则状态方程dp[i][j][k] = max{dp[i-1][k][r]+cnt[j]  | 状态i,j,k要能够共存}(cnt[j]为j在二进制下的1的个数,即士兵数)。第一维可以压缩为2,即两种状态交替进行(这里没有压缩)。

对于每一行可能出现的组合,可预处理出每一种有效状态。

#include<iostream>
using namespace std;

int row[110];
int dp[110][220][220]; //dp[i][j][k]表示第i行状态为j,i-1行状态为k时的士兵最大值
int s[1<<11];        //合法状态
int cnt[1<<11];      //合法状态中1的个数,即可安排的士兵数

int get_cnt(int x)
{
	int c=0;

	while(x>0)
	{
		c++;
		x=x&(x-1);
	}
	return c;
}

int sovle(int n,int m)
{
	int state;     //一行一开始可安排士兵的合法状态总数(处理左右曼哈顿距离等于2的情况)
	int i,j,k,l,ans;

	state=0;
	for(i=0;i<(1<<m);i++)  //每行总的状态有2^m
	{
		if(i&(i<<2)) continue;  //若有曼哈顿相距为2的情况则排除
		s[state]=i;
		cnt[state++]=get_cnt(i);
	}
	for(i=0;i<state;i++)           //第0行
	{
		if(s[i]&row[0]) continue;  //row存的是不能安排士兵的情况
		dp[0][i][0]=cnt[i];
	}
	for(i=1;i<n;i++)  //每一行
		for(j=0;j<state;j++)
		{
			if(s[j]&row[i]) continue; //是否能够安排士兵
			for(k=0;k<state;k++)  //i-1行信息
			{
				if((s[j]&(s[k]>>1))||(s[j]&(s[k]<<1))) continue;//对角
				for(l=0;l<state;l++) //i-2行信息
				{
					if(s[j]&s[l]) continue;   //垂直
					dp[i][j][k]=dp[i][j][k]>dp[i-1][k][l]+cnt[j]?dp[i][j][k]:dp[i-1][k][l]+cnt[j];
				}
			}
		}
	ans=0;
	for(i=0;i<state;i++)             //枚举找到最大值
		for(j=0;j<state;j++)
			ans=ans>dp[n-1][i][j]?ans:dp[n-1][i][j];
	return ans;
}

int main()
{
	int n,m,i,j,x;

	while(scanf("%d%d",&n,&m)==2)
	{
		memset(row,0,sizeof(row));
		memset(dp,0,sizeof(dp));
		for(i=0;i<n;i++)
			for(j=0;j<m;j++)
			{
				scanf("%d",&x);
				if(!x) row[i]=(row[i]<<1)|1;  //一开始不可放士兵的位置设为1,方便后面检测
				else
					row[i]<<=1;       //可放士兵的位置不做处理
			}
		printf("%d\n",sovle(n,m));
	}
    return 0;
}
时间: 2024-12-26 11:20:30

HDU ACM 4539 郑厂长系列故事——排兵布阵->状态压缩DP的相关文章

HDU 4539 郑厂长系列故事——排兵布阵 (状态压缩DP)

中文题,题意不再累赘. 思路:对于第 i 行的放士兵,影响它的只有第 i-1 行和 i-2 行,所以暴力枚举符合这三行的状态 state[i],state[j],state[k].  接下来就是二进制的巧妙应用了. 具体题解看代码注释!!! #include<cstdio> #include<stdlib.h> #include<string.h> #include<string> #include<map> #include<cmath&

HDU 4539 郑厂长系列故事――排兵布阵(状态压缩)

郑厂长系列故事--排兵布阵 Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) Total Submission(s): 1954    Accepted Submission(s): 701 Problem Description 郑厂长不是正厂长 也不是副厂长 他根本就不是厂长 事实上 他是带兵打仗的团长 一天,郑厂长带着他的军队来到了一个n*m的平原准备布阵. 根据以往的战

HDU 4539 郑厂长系列故事——排兵布阵 &lt;&lt;状压dp

思路 被这道题折磨死了,只是发上来纪念一下,思路同方格取数(1),我已经疯了! 代码 1 #include<bits/stdc++.h> 2 using namespace std; 3 int maze[110][15]; 4 int n,m; 5 vector<int> all[110]; 6 int dp[110][200][200]; 7 int num[1<<10]; 8 bool check(int r,int state) 9 { 10 for(int i

HDU 4539 郑厂长系列故事——排兵布阵

http://acm.hdu.edu.cn/showproblem.php?pid=4539 郑厂长系列故事——排兵布阵 Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)Total Submission(s): 1708    Accepted Submission(s): 620 Problem Description 郑厂长不是正厂长 也不是副厂长 他根本就不是厂长 事实上

HDU 4539郑厂长系列故事――排兵布阵(状压DP)

HDU 4539  郑厂长系列故事――排兵布阵 基础的状压DP,首先记录先每一行可取的所哟状态(一行里互不冲突的大概160个状态), 直接套了一个4重循环居然没超时我就呵呵了 1 //#pragma comment(linker,"/STACK:102400000,102400000") 2 #include <map> 3 #include <set> 4 #include <stack> 5 #include <queue> 6 #i

HDU 4539 郑厂长系列故事――排兵布阵

/* 曼哈顿距离的定义是:两个点的坐标为(x1,y1),(x2,y2),两点的曼哈顿距离为|x1-x2|+|y1-y2| 题意:题上要求是两个士兵的距离不能是曼哈顿距离为2,意思就是这个点在同一行同一列不能相间,这个点的左上,左下,右上,右下角不能有 士兵. 思路:dp+状态压缩dp[i][j][k]定义的状态为i是当前行,j为当前行的状态,k为上一行的状态类似炮兵阵地 */ #include<stdio.h> #include<string.h> #define Max(a,b)

[状压dp]HDOJ4539 郑厂长系列故事——排兵布阵

中文题,题意不再赘述 对于“?”这一格,它所能攻击到的(曼哈顿距离为2的) 前方的 即“√”的四个位置 那么与此格有关的即它前方两行(即状压这两行) 首先预处理每行能满足的: i 和(i<<2)不能同时放 然后分别枚举前一行和再前一行的所有状态(每一行的状态至多只有2^10=1024个) 判断能否共存 注意mp==1处才能放,mp==0处不能放 HDOJ 4539

HDU ACM 4511 小明系列故事——女友的考验-&gt;AC自动机+DP

分析:参考别人的搞. 1.AC自动机: 使用AC自动机来压缩路段,如禁掉的路段是1->2->3,那么插入字符串(123) ,注意点只有1~50,所以0~50用ASCII 压缩成字符串即可. 这样就能够完成禁止路段的在线状态转移. 2.DP部分: 两点之间的最短路.dp[i][j]表示在地点i,当前字符是j的状态. 初始化:fill(&dp0][0],&dp[maxn-1][maxp-1],inf),inf=1e12,memset不能用. 边界:首先找出出发点在Pool中的位置,

HDU ACM 4507 吉哥系列故事——恨7不成妻 -&gt;数位DP

题意:如果一个整数符合下面3个条件之一,那么我们就说这个整数和7有关-- 1.整数中某一位是7: 2.整数的每一位加起来的和是7的整数倍: 3.这个整数是7的整数倍: 现在问题来了:吉哥想知道在一定区间内和7无关的数字的平方和. 分析:数位DP,关键内容如下. (pre0+i)%7用于处理各个位数之和时候为7的倍数,(pre1*10+i)%7用于处理这个数是否为7的倍数. #include<iostream> using namespace std; const __int64 mod=100