您的位置:首页 > 其它

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

2013-04-27 09:40 288 查看
硬着头皮写了两天,下面把思路复述一下:

一:状态的表示:

对于每一行来说,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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: