hdu 2167 题解

题目

题意

一个数字正方形(所有数都是两位的正整数),取了一个数后,它的周围 $ 8 $ 个数都不能被选,问最大取数总和。

注意数据范围 $ 3=< n <=15 $ 我们可能一开始会去想暴力搜索,枚举状态,但很容易发现时间复杂度过高过不去,于是可以去想dp,先预处理出可行状态,然后枚举可行状态,以及行数,进行转移即可。

我们定义 $ f[i][j] $ 表示当前在第 $ i $ 行此时状态为 $ j $ 状态先处理出来这里只要存编号就好了

转移方程 $ f[i][k]=max(f[i][k],f[i-1][j]+sum) $

$ sum \(表示\) k $行所有可以可以取出来的数的和( $ j $是 $ k $ 的上一行

还有一些判断可行的条件看代码吧

另外就是这一题的读入比较搞人,多试试就好了

代码

#include<bits/stdc++.h>
using namespace std;
int dp[16][1600],mape[16][16],sta[1600];
int n;
char s[100];
void star(){
	n=0;
	memset(dp,0,sizeof(dp));
	memset(mape,0,sizeof(mape));
	memset(sta,0,sizeof(sta));
}
void solve(){
	int cnt=0;
	for(int i=0;i<(1<<n);++i){
		if((!(i&(i<<1)))&&(!(i&(i>>1)))) sta[++cnt]=i;
	}
	for(int i=1;i<=n;++i){//行数
		for(int j=1;j<=cnt;++j){//上一行的状态
			for(int k=1;k<=cnt;++k){//这一行的状态
				if((!(sta[k]&sta[j]))&&(!(sta[k]&(sta[j]>>1)))&&(!(sta[k]&(sta[j]<<1)))){//保证不冲突
					int sum=0;
					for(int u=0;u<n;++u){
						if(sta[k]&(1<<u)){//可以取数
							sum+=mape[i][n-u-1];//这里是n-u-1,因为二进制第u位在图上是n-u-1位
						}
						dp[i][k]=max(dp[i][k],dp[i-1][j]+sum);
					}
				}
			}
		}
	}
	int ans=0;
    for(int i=1;i<=cnt;i++) ans=max(ans,dp[n][i]);
    printf("%d\n",ans);
}
int main(){
	while(gets(s)){
		star();
		int t=strlen(s);
		for(int i=0;i<t;i+=3){
			mape[1][n++]=(s[i]-'0')*10+(s[i+1]-'0');
		}
		for(int i=2;i<=n;++i){
			for(int j=0;j<n;++j){
				scanf("%d",&mape[i][j]);
			}
		}
		solve();
		getchar();getchar();
	}
	return 0;
}
posted @ 2019-10-25 19:25  End_donkey  阅读(107)  评论(0编辑  收藏  举报