http://acm.hdu.edu.cn/showproblem.php?pid=4539
状态压缩+dp
此题给人感觉状态数比较多 但是由于自身有一定的限制所以说 根本不到(1<<10) 自己测一下的话还不到 200
如果再加上输入矩阵的限制 每一行的状态数就更少了 大胆的用for循环就是了
可怜的是我在比赛中大脑短路没想到
用了一种很恶心的方法 就是把图斜着看 根据左下到右上的方向进行分层,这样第i层只和第i-2层有关了
不过在将图斜过来的时候要细心呐
代码1:
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<map> #include<set> #include<vector> #include<stack> #include<queue> #include<algorithm> #define LL long long #define ULL unsigned long long using namespace std; const int INF=0x3f3f3f3f; const int MOD=1000000007; const int N=105; const int M=205; int a[N][N]; int b[N],len,b1[N],len1; int can[1<<10][1<<10]; vector<int>vt[N]; int dp[N][M][M]; bool ok(int x,int y) { len=0; while(y>0) { b[len++]=(y&1); y=y>>1; } for(int i=0;i<len;++i) if(b[i]==1&&((i-2>=0&&b[i-2]==1)||(a[x][i+1]==0))) return false; return true; } int fcan(int x,int y) { len=0; while(x>0) { b[len++]=(x&1); x=x>>1; } len1=0; while(y>0) { b1[len1++]=(y&1); y=y>>1; } int sum=0; for(int i=0;i<len1;++i) if(b1[i]==1) { ++sum; if(i-1>=0&&i-1<len&&b[i-1]==1) return -1; if(i+1>=0&&i+1<len&&b[i+1]==1) return -1; } return sum; } int main() { //freopen("data.in","r",stdin); for(int i=0;i<(1<<10);++i) for(int j=0;j<(1<<10);++j) can[i][j]=fcan(i,j); int n,m; while(cin>>n>>m) { for(int i=0;i<=n;++i) vt[i].clear(); memset(a,0,sizeof(a)); for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) cin>>a[i][j]; for(int i=1;i<=n;++i) for(int j=0;j<(1<<m);++j) if(ok(i,j)) vt[i].push_back(j); vt[0].push_back(0); memset(dp,-1,sizeof(dp)); for(unsigned int j=0;j<vt[1].size();++j) dp[1][0][j]=can[vt[0][0]][vt[1][j]]; for(int i=2;i<=n;++i) for(unsigned int j=0;j<vt[i-1].size();++j) for(unsigned int l=0;l<vt[i].size();++l) if(can[vt[i-1][j]][vt[i][l]]!=-1) {//cout<<"T"<<endl; for(unsigned int r=0;r<vt[i-2].size();++r) if(can[vt[i-2][r]][vt[i-1][j]]!=-1&&dp[i-1][r][j]!=-1&&(vt[i][l]&vt[i-2][r])==0) { if(dp[i][j][l]==-1||dp[i][j][l]<dp[i-1][r][j]+can[vt[i-1][j]][vt[i][l]]) dp[i][j][l]=dp[i-1][r][j]+can[vt[i-1][j]][vt[i][l]]; } } int ans=0; for(unsigned int j=0;j<vt[n-1].size();++j) for(unsigned int l=0;l<vt[n].size();++l) if(dp[n][j][l]!=-1) ans=max(ans,dp[n][j][l]); printf("%d\n",ans); } return 0; }
代码2:
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<map> #include<set> #include<vector> #include<stack> #include<queue> using namespace std; const long long MOD=1000000007; const int N=310; const int M=(1<<10); int dp[N][M]; int b[N][N]; int a[N][N]; int can[N][M]; bool CC[M][M]; int m,n; int b1[N],len1,b2[N],len2; void To() { for(int i=1;i<=n;++i) { int r=1; int x=i,y=1; for(;x>0&&r<=m;--x,++y,r++) a[i][r]=b[x][y]; } for(int j=2;j<=m;++j) { int r=j; int x=n,y=j; for(;x>0&&r<=m;--x,++y,++r) a[n+j-1][r]=b[x][y]; } } int Fcan(int x,int y) { len1=0; while(y>0) { b1[len1++]=(y&1); y=y>>1; } int sum=0; for(int i=0;i<len1;++i) if(b1[i]==1) { ++sum; if(i-1>=0&&b1[i-1]==1) return -1; if(a[x][i+1]==0) return -1; } return sum; } bool FCC(int x,int y) { len1=0; while(x>0) { b1[len1++]=(x&1); x=x>>1; } len2=0; while(y>0) { b2[len2++]=(y&1); y=y>>1; } for(int i=0;i<len2;++i) if(b2[i]==1) { if(i-1>=0&&i-1<len1&&b1[i-1]==1) return false; if(i-2>=0&&i-2<len1&&b1[i-2]==1) return false; if(i>=0&&i<len1&&b1[i]==1) return false; } return true; } int main() { //freopen("data.in","r",stdin); while(scanf("%d %d",&n,&m)!=EOF) { memset(dp,0,sizeof(dp)); memset(a,0,sizeof(a)); memset(b,0,sizeof(b)); for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) scanf("%d",&b[i][j]); To(); int h=(1<<m); int E=n+m-1; for(int i=1;i<=E;++i) for(int j=0;j<h;++j) can[i][j]=Fcan(i,j); for(int i=0;i<h;++i) for(int j=0;j<h;++j) CC[i][j]=FCC(i,j); memset(dp,0,sizeof(dp)); for(int i=1;i<=E;++i) for(int j=0;j<h;++j) { if(can[i][j]==-1) continue; if(i<=2) {dp[i][j]=can[i][j];continue;} for(int l=0;l<h;++l) if(can[i-2][l]!=-1) { if(CC[l][j]) { //if(i==8) //cout<<i<<" "<<l<<" "<<j<<endl; dp[i][j]=max(dp[i][j],dp[i-2][l]+can[i][j]); } } } int ans1=0,ans2=0; for(int j=0;j<h;++j) { ans1=max(ans1,dp[E-1][j]); ans2=max(ans2,dp[E][j]); } printf("%d\n",ans1+ans2); } return 0; }