POJ--1038--Bugs Integrated, Inc.--状态DP

33 篇文章 1 订阅

硬着头皮写了两天,下面把思路复述一下:

一:状态的表示:

对于每一行来说,a[x]={0,1,2};分别表示格点x的上方有{0,1,2}个空格可用。和黑书的不一样,我觉得这样表示比较方便直观一点就这样表示了。

然后对于每一行可看做是一个三进制的数字,再把这个三进制数转换成十进制数字,从而实现状态压缩存储的目的。

二:dp 数组的表示:dp[i][j] 表示从第i-1行的任意状态得到的第i行的 j 状态,第i-1能够放置的最大芯片数量,理解了这个状态表示这个题就会了~~如果你实在是理解不了,可以看一下其他人的状态表示,或者直接看代码也可以(思路在第二份有注释的代码里面)。

三:用滚动数组节省空间

下面这个没有注释的代码是在第一次写出来怎么调试都WA的情况重新写的,AC了

#include<iostream>
#include<cstring>
#include<cstdio>
#define M(a) memset((a),0,sizeof((a)))
#define maxn 160
#define maxs 60000
#define dbug1
using namespace std;
int bmp[maxn][maxn];
int n,m,bp;
int st[3][maxs];
int sc[3];
int dp[3][maxs];
int sq3[]={1,3,9,27,81,243,729,2187,6561,19683,59049};
int curStatu;
bool visStatus[maxs];
int temp_dp;

void init()
{
	int x,y;
	M(bmp);M(st);M(sc);
	scanf("%d%d%d",&n,&m,&bp);
	while(bp--)
	{
		scanf("%d%d",&x,&y);
		bmp[x][y]=1;
	}
}
void get_Status(int *pre,int u)
{
	memset(pre,0,sizeof(int)*(m+1));
	int c=m;
	while(u)
	{
		pre[c]=u%3;
		u/=3;
		c--;
	}
}
void dfs(int r,int pre[],int cl,int code,int num)
{
	if(cl>m)
	{
		if(!visStatus[code])
		{
			st[2][sc[2]++]=code;
			visStatus[code]=1;
		}
		dp[2][code]=max(dp[2][code],temp_dp+num);
	}
	else if(bmp[r][cl])
	{
		dfs(r,pre,cl+1,code,num);
	}
	else
	{
		if(cl+1<=m&&bmp[r][cl+1]==0&&pre[cl]>1&&pre[cl+1]>1)
		{
			dfs(r,pre,cl+2,code,num+1);
		}
		if(cl+2<=m&&((bmp[r][cl+1]+bmp[r][cl+2])==0)&&pre[cl]>0&&pre[cl+1]>0&&pre[cl+2]>0)
		{
			dfs(r,pre,cl+3,code,num+1);
		}
		code+=pre[cl]>0?2*sq3[m-cl]:sq3[m-cl];
		dfs(r,pre,cl+1,code,num);
	}
}
void solve()
{
	sc[1]=1;M(dp);
	int pre[12];
	
	for(int i=1;i<=n;i++)
	{
		M(visStatus);
		for(curStatu=0;curStatu<sc[1];curStatu++)
		{
			temp_dp=dp[1][st[1][curStatu]];
			get_Status(pre,st[1][curStatu]);
			dfs(i,pre,1,0,0);
		}
		for(int j=0;j<sc[2];j++)
		{
			st[1][j]=st[2][j];
		}
		sc[1]=sc[2];sc[2]=0;M(st[2]);
		M(dp[1]);
		for(int j=0;j<sc[1];j++)
		{
			dp[1][st[1][j]]=dp[2][st[1][j]];
		}
		M(dp[2]);
		#ifdef dbug
		int tans=0;
		for(int j=0;j<sc[1];j++)
		{
			tans=max(tans,dp[1][st[1][j]]);
		}
		printf("%d ---> %d\n",i,tans);
		#endif
	}
	int ans=0;
	for(int i=0;i<sc[1];i++)
	{
		ans=max(ans,dp[1][st[1][i]]);
	}	
	printf("%d\n",ans);
}


int main()
{
	#ifdef dbug
	freopen("1038.txt","r",stdin);
	#endif
	int T;
	scanf("%d",&T);
	while(T--)
	{
		init();
		solve();
	}
	return 0;
}

下面的这个代码是调试到死都过不了的代码,加了很多的注释,思路可以看一下这里。另外如果你知道这份代码哪里修改了可以过掉这题,请告诉我,谢谢。(楼主已经找到错误了。。。。)

#define dbug1
#include<iostream>
#include<cstring>
#include<cstdio>
#define maxn 120	//这是后来楼主加的,数组开小了,尼玛。。。POJ给WA不给RE,坑爹啊
#define maxs 60000
#define M(a) memset((a),0,sizeof((a)))
using namespace std;
int n,m;	// the height and width
int bp;		//the number if bad point
int bmp[maxn][maxn];	//the map with binary  style
int dp[3][maxs];		//dp[i][j]表示第 i 行状态为 j 时的最大放置数量 
int st[3][maxs];	//压缩存储每一行的状态 
int sc[3];			//每一行的状态数量 
int curStatu;       		//深搜时的父状态 
bool visStatu[maxs];	//记录深搜状态是否到达过 
const int sq3[]={1,3,9,27,81,243,729,2187,6561,19683,59049};
/**************** 
* 状态表示 : pre[i] 表示当前格点的上方有几个格点是空置的
*****************/ 
void init()
{
	int x,y;
	M(bmp);M(st);M(sc);
	//data input 
	scanf("%d%d%d",&n,&m,&bp);
	while(bp--)
	{
		scanf("%d%d",&x,&y);
		bmp[x][y]=1;
	}
}
void get_statu(int pre[],int u)
{
	//将压缩后的状态 u 解压缩后存储在pre 数组返回 
	int c=m;
	memset(pre,0,sizeof(int)*12);	//此时pre是指针,而不是数组首地址,sizeof(pre)为4 
	while(u)
	{
		pre[c]=u%3;
		u/=3;
		c--;
	}
}
int temp_dp;	//存储父状态curStatu 能放置的最大芯片数量  
void dfs(int r,int pre[],int cl,int code,int num)//r 当前行,pre[]每个格点的状态 ,cl 当前列 
{						//code 当前状态压缩编码,num 表示沿父状态深搜到当前状态新增加的芯片数量 
	if(cl>m)	//深搜边界 
	{
		if(!visStatu[code]) 
		{
			visStatu[code]=1; 
			st[2][sc[2]++]=code;	//下一行的新状态 
		} 
		/*if(temp_dp+num>dp[1][st[1][curStatu]]) //更新当前行 curStatu 状态能放置的最大芯片数量 
		{
			dp[1][st[1][curStatu]]=temp_dp+num;
		}*/
		dp[2][code]=max(dp[2][code],temp_dp+num);	//此时的dp[2][code]记录的是下一行到达code状态时 													//上一行的最大放置数量
	}
	else if(bmp[r][cl])  	//坏点,不放。 
	{
		dfs(r,pre,cl+1,code,num);
	}
	else
	{
		if(cl+1<=m&&bmp[r][cl+1]==0&&pre[cl]>1&&pre[cl+1]>1)//符合放置宽为2,高为3 的芯片 
		{
			dfs(r,pre,cl+2,code,num+1);
		}
		//放置宽为3 ,高为2 的芯片 
		if(cl+2<=m&&(bmp[r][cl+1]+bmp[r][cl+2]==0)&&pre[cl]>=1&&pre[cl+1]>=1&&pre[cl+2]>=1)
		{
			dfs(r,pre,cl+3,code,num+1);
		}
		
		//当前格点,不放。 
		code+=pre[cl]>=1?2*sq3[m-cl]:sq3[m-cl];
		dfs(r,pre,cl+1,code,num);
	}
}
void solve()
{
	int pre[12],code;
	M(dp);
	sc[1]=1;	//第一行只有一种状态,上方空置格点为0
	
	//滚动数组,index=1 是当前行,index =2 是下一行 
	for(int i=1;i<=n;i++)
	{
		M(visStatu); 	//下一行的所有状态都没有出现过 
		for(curStatu=0;curStatu<sc[1];curStatu++) //当前行的状态数量,curStatu是全局变量 
		{
			get_statu(pre,st[1][curStatu]);		//状态解压缩 
			temp_dp=dp[1][st[1][curStatu]];     //temp_dp是上一行能走到当前状态的最大芯片数量 
			dfs(i,pre,1,0,0);  
		}
		
		//数组滚动操作 
		for(int j=0;j<sc[2];j++)	//状态滚啊滚,向上滚 
		{
			st[1][j]=st[2][j];
		}
		sc[1]=sc[2];sc[2]=0;M(st[2]);
		M(dp[1]);
		
		//dp 数组滚啊滚 
		for(int j=0;j<sc[1];j++)
		{
			dp[1][st[1][j]]=dp[2][st[1][j]];
		}
		
		M(dp[2]);
	}	
	//find answer 
	int ans=0;
	for(int i=0;i<sc[1];i++)
	{
		ans=max(ans,dp[1][st[1][i]]);
	}
	printf("%d\n",ans);
}
int main()
{
	freopen("1038.txt","r",stdin);
	int T;
	scanf("%d",&T);
	while(T--)
	{
		init();
		solve();
	}
	return 0;
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值