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了
下面的这个代码是调试到死都过不了的代码,加了很多的注释,思路可以看一下这里。另外如果你知道这份代码哪里修改了可以过掉这题,请告诉我,谢谢。(楼主已经找到错误了。。。。)
一:状态的表示:
对于每一行来说,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; }
相关文章推荐
- POJ 1038 Bugs Integrated, Inc. (状态dp)
- poj 1038 Bugs Integrated, Inc. __dp状态压缩
- Poj1038 Bugs Integrated, Inc.【状态压缩DP】
- POJ 1038 Bugs Integrated, Inc. 状态压缩DP
- poj 1038 Bugs Integrated, Inc. __dp状态压缩
- POJ 1038 - Bugs Integrated, Inc. 三进制状态DP
- CEOI 2002, POJ 1038 Bugs Integrated, Inc. 状态压缩 DP
- poj 1038 Bugs Integrated, Inc. 状态压缩dp
- poj 1038 - Bugs Integrated, Inc.(状态压缩dp)
- poj 1038 Bugs Integrated, Inc.(动态规划状态压缩)
- 【DP,状态压缩】PKU-1038-Bugs Integrated, Inc.
- POJ 1038 Bugs Integrated, Inc.(状态压缩)
- poj 1038 Bugs Integrated, Inc.(状压dp)
- POJ 1038 Bugs Integrated(状态压缩DP)
- poj 1038 Bugs Integrated, Inc. 三进制状态压缩 DFS 滚动数组
- POJ 1038 Bugs Integrated, Inc. ——状压DP
- POJ 1038 Bugs Integrated, Inc. 状态压缩dp+3进制枚举
- POJ 1038 Bug Integrated Inc(状态压缩DP)
- poj 1038 Bugs Integrated, Inc. 状态DP+四进制+DFS
- poj 1038 Bugs Integrated, Inc.