2016夏季练习——dp

来源:POJ1185

对于影响因素的个数来判断需要的维度,根据状态的多少来开辟数组

对于各个状态进行一个比较,注意使用压缩的方法对于问题中的所有东西进行优化

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int n,m;
const int N=100+5;
const int M=10;
const int MAXN= (1<<10)+5;

int dp[N][N][N];
//dp[floor][prestate][currstate]
int mp[N];
char ch;
int st[100];
int sum[100];
/*
dp关键是要找出那些量杜宇当前状态的决策会产生影响,而这个影响的种类往往确定维度
dp[r][i][j]=max{dp[r-1][j][k]}+sum[i]
*/
bool judge(int x){
	if(x&(x<<1)) return false;
	if(x&(x<<2)) return false;
	return true;
}
int asksum(int x){
	int cnt=0;
	while(x>0){
		if(x&1) cnt++;
		x>>=1;
	}
	return cnt;
}
int main(){
	while(scanf("%d%d",&n,&m)!=EOF){
		getchar();
		memset(mp,0,sizeof(mp));
		for(int i=0;i<n;i++){
			for(int j=0;j<m;j++){
				scanf("%c",&ch);
				if(ch=='H'){
					mp[i]|=(1<<j);
					//cout<<i<<" "<<j<<endl;
				}
				//cout<<ch;
			}
			getchar();
			//cout<<endl;
		}
		memset(dp,-1,sizeof(dp));
		int k=0;
		for(int j=0;j<(1<<m);j++){
			if(judge(j)){
				st[k]=j;
				sum[k++]=asksum(j);
				//cout<<sum[k-1]<<endl;
			}
		}
		//cout<<"k: "<<k<<endl;
		for(int i=0;i<k;i++)
			if(!(mp[0]&st[i])) {//youdu
				dp[0][0][i]=sum[i];
				//cout<<sum[i]<<endl;
			}

		for(int floor=1; floor<n; floor++){
			for(int stn1=0; stn1<k; stn1++){
				if(st[stn1] & mp[floor]) continue;
				//cout<<"dd"<<endl;
				for(int stn2=0; stn2<k; stn2++){
					if(st[stn1] & st[stn2]) continue;
					//cout<<"kk"<<endl;
					for(int stn3=0; stn3<k; stn3++){
						if(st[stn1] & st[stn3]) continue;
						//cout<<"cc"<<endl;
						if(dp[floor-1][stn3][stn2]==-1) continue;
						dp[floor][stn2][stn1]=max(dp[floor][stn2][stn1],dp[floor-1][stn3][stn2]+sum[stn1]);
						/*if(floor==n-1) {
							cout<<dp[n-1][stn2][stn1]<<endl;
						}*/
					}
				}
			}
		}
		//cout<<"-----------"<<endl;
		int ans=0;
		for(int i=0;i<k;i++){
			for(int j=0;j<k;j++){
				ans=max(ans,dp[n-1][i][j]);
				//cout<<dp[n-1][i][j]<<endl;
			}
		}
		cout/*<<"ans: "*/<<ans<<endl;
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值