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>
#include<iostream>
#include <queue>
#include <stack>
#include<algorithm>
#include<set>
using namespace std;
#define INF 1e8
#define inf -0x3f3f3f3f
#define eps 1e-8
#define LL long long
#define N 100001
#define mol 100000000

int lp(int a,int b)
{
	return a&b;
}
int dp[105][200][200];//dp[i][j][k],表示第 i 行是 state[j]状态i-1行是state[k]状态的最大值
int state[200];//符合规定的状态
int base[200];//给定矩阵的初始状态
int sum[200];//sum[i]:状态satet[i]的士兵数
int n,m,g;
int main()
{
	while(~scanf("%d%d",&n,&m))
	{
		memset(base,0,sizeof(base));
        memset(dp,0,sizeof(dp));
        memset(state,0,sizeof(state));
        memset(sum,0,sizeof(sum));
		if(n==0||m==0)
		{
			printf("0\n");
			continue;
		}
		for(int i=0;i<n;i++)
		{
			for(int j=0;j<m;j++)
			{
				scanf("%d",&g);
				if(g==0)
					base[i]+=1<<(j);//初始状态二进制表示
			}
		}
		int num=0;
		for(int i=0;i<(1<<m);i++)
		{
			if(lp(i,i<<2)||lp(i,i>>2)) continue;//状态i要满足它不能攻击它的前两个和后两个
			int k=i;
			while(k)//算出k有多少个1(士兵)
			{
				sum[num]+=k&1;
				k=k>>1;
			}
			state[num++]=i;
		}
		for(int i=0;i<num;i++)//初始第0行的状态
		{
			if(lp(state[i],base[0])) continue;
			dp[0][i][0]=sum[i];
		}
		for(int i=0;i<num;i++)//在满足第0行的状态下寻找第1行的状态
		{
			if(lp(state[i],base[1])) continue;
			for(int j=0;j<num;j++)
			{
				if(lp(state[j],base[0])) continue;
				if(lp(state[j]<<1,state[i])||lp(state[j]>>1,state[i])) continue;
				dp[1][i][j]=max(dp[1][i][j],dp[0][j][0]+sum[i]);
			}
		}
		for(int i=0;i<num;i++)//在满足第0,1行的状态下寻找第2行的状态
		{
			if(lp(state[i],base[2])) continue;
			for(int j=0;j<num;j++)
			{
				if(lp(state[j],base[1])) continue;
				for(int k=0;k<num;k++)
				{
					if(lp(state[k],base[0])) continue;
					if(lp(state[i]<<1,state[j])||lp(state[i]>>1,state[j])) continue;
					if(lp(state[j]<<1,state[k])||lp(state[j]>>1,state[k])) continue;
					if(lp(state[i],state[k])) continue;
					dp[2][i][j]=max(dp[2][i][j],dp[1][j][k]+sum[i]);
				}
			}
		}
		for(int r=3;r<n;r++)//从第3行开始
		{
			for(int i=0;i<num;i++)//暴力枚举三行的状态state[i],state[j],state[k]
			{
				if(lp(base[r],state[i])) continue;
				for(int j=0;j<num;j++)
				{
					if(lp(base[r-1],state[j])) continue;
					if(lp(state[i]<<1,state[j])||lp(state[i]>>1,state[j])) continue;
					for(int k=0;k<num;k++)
					{
						if(lp(base[r-2],state[k])) continue;
						if(lp(state[j]<<1,state[k])||lp(state[j]>>1,state[k])) continue;
						if(lp(state[i],state[k])) continue;
						dp[r][i][j]=max(dp[r-1][j][k]+sum[i],dp[r][i][j]);
					}
				}
			}
		}
		int ans=0;
		for(int i=0;i<num;i++)
		{
			for(int j=0;j<num;j++)
				ans=max(ans,dp[n-1][i][j]);
		}
		printf("%d\n",ans);
	}
	return 0;
}
/*
6 6
1 0 0 0 0 1
0 0 0 0 0 0
0 0 1 1 0 0
0 0 1 1 0 0
0 0 1 1 0 0
1 0 1 1 0 1

3 3
1 1 1
1 1 1
1 1 1

6 6
0 0 0 0 0 0
0 0 0 0 0 0
0 0 1 1 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0

6 6
1 1 1 1 1 1
1 1 1 1 1 1
1 1 1 1 1 1
1 1 1 1 1 1
1 1 1 1 1 1
1 1 1 1 1 1

0 6

1 6
1 1 1 1 1 1

2 6
1 1 1 1 1 1
1 1 1 1 1 1

Answer:
6
3
2
12
0
4
4
*/

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

时间: 2024-08-03 18:26:46

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

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 ACM 4539 郑厂长系列故事——排兵布阵-&gt;状态压缩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的个数,即士兵数).第一

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郑厂长系列故事――排兵布阵(状压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 郑厂长系列故事——排兵布阵

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 郑厂长系列故事――排兵布阵

/* 曼哈顿距离的定义是:两个点的坐标为(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 - 4529 郑厂长系列故事――N骑士问题 (状态压缩DP)

Description 郑厂长不是正厂长 也不是副厂长 他根本就不是厂长 还是那个腾讯公司的码农 一个业余时间喜欢下棋的码农 最近,郑厂长对八皇后问题很感兴趣,拿着国际象棋研究了好几天,终于研究透了.兴奋之余,坐在棋盘前的他又开始无聊了.无意间,他看见眼前的棋盘上只摆了八个皇后,感觉空荡荡的,恰好又发现身边还有几个骑士,于是,他想把这些骑士也摆到棋盘上去,当然棋盘上的一个位置只能放一个棋子.因为受八皇后问题的影响,他希望自己把这些骑士摆上去之后,也要满足每2个骑士之间不能相互攻击. 现在郑厂长想

[AC自动机+状压dp] hdu 4534 郑厂长系列故事——新闻净化

题意:中文的题目,意思就是说有很多串,每个串都有权值,权值为999的串必须出现,-999的串必须不出现.权值在-999~999之间. 然后必须出现的串不超过8个.然后给一个全为小写目标串,问最少需要删除多少个字母才能够保证必须出现的串都出现,次数一样保证权值最大.输出次数和权值. 然后根据样例,那些必须出现的串,其实权值是0. 思路: 很明显一开始建自动机构成trie图,但是需要注意的就是mark和sum的更新.个人是把所有中间的节点的sum全部赋值成了-inf. 接着只有8个必须出现的串,所以