您的位置:首页 > 其它

[BZOJ1187][HNOI2007] 神奇游乐园 - 插头DP

2016-11-04 00:26 344 查看
这么裸的题调得我一脸懵逼 - - 我太弱啦

#include"bits/stdc++.h"
#define F(i,l,r) for(register int i=l;i<=r;i++)
#define readi(x) scanf("%d",&x)
using namespace std;
const int N=105,M=7,S=3005,inf=0x3f3f3f3e;
int dp
[M][S],n,m,w
[M],lim,st[S],rk[2<<2*M+2],cnt[2<<2*M],ans=-inf;
void build_status(){
F(i,0,(1<<2*m+2)-1){
int p=i,s=0;
bool flag=true;
while (p){
if(p%4==3){flag=false;break;}
if(p%4==1)s++,cnt[i]++;if(p%4==2)s--;
p>>=2;if(s<0){flag=false;break;}
}
if(s)flag=false;
if(flag)st[++lim]=i,rk[i]=lim;
}
}
int main(){
readi(n),readi(m);build_status();
F(i,1,n)F(j,1,m)readi(w[i][j]);
F(i,1,n)F(j,0,m)F(k,1,lim)dp[i][j][k]=-inf;
dp[1][0][1]=0;
F(i,1,n){
F(j,0,m-1)F(k,1,lim)if(dp[i][j][k]>-inf){
int s1=(st[k]>>2*j)&3; //左插头
int s2=(st[k]>>2*j+2)&3; //上插头
if (s1==1 && s2==2){ //插头组成回路 : 若只有一条回路记录答案 多条回路直接continue
if (cnt[st[k]]==1) ans=max(ans,dp[i][j][k]+w[i][j+1]);
else continue;
} else if (s1==2 && s2==1){ //两区间合并
int p=rk[st[k]-(s1<<2*j)-(s2<<2*j+2)];
dp[i][j+1][p]=max(dp[i][j+1][p],dp[i][j][k]+w[i][j+1]);
} else if (!s1 && !s2){ //空的
int p1=k,p2=rk[st[k]+(1<<2*j)+(2<<2*j+2)];
dp[i][j+1][p1]=max(dp[i][j+1][p1],dp[i][j][k]);
dp[i][j+1][p2]=max(dp[i][j+1][p2],dp[i][j][k]+w[i][j+1]);
} else if (!s1 || !s2){ //一端为空
int p1=k,p2=s1?rk[st[k]+(3*s1<<2*j)]:rk[st[k]-(3*s2<<2*j)];
dp[i][j+1][p1]=max(dp[i][j+1][p1],dp[i][j][k]+w[i][j+1]);
dp[i][j+1][p2]=max(dp[i][j+1][p2],dp[i][j][k]+w[i][j+1]);
} else { //均为1或均为2
if (s1&1){ //上插头的对应插头变成1
int p=j+2;while(((st[k]>>2*p)&3)!=2)p++;
p=rk[st[k]-(1<<2*p)-(s1<<2*j)-(s2<<2*j+2)];
dp[i][j+1][p]=max(dp[i][j+1][p],dp[i][j][k]+w[i][j+1]);
} else { //左插头的对应插头变成2
int p=j-1;while(((st[k]>>2*p)&3)!=1)p--;
p=rk[st[k]+(1<<2*p)-(s1<<2*j)-(s2<<2*j+2)];
dp[i][j+1][p]=max(dp[i][j+1][p],dp[i][j][k]+w[i][j+1]);
}
}
}
if(i!=n)F(k,1,lim)if(rk[st[k]<<2])
dp[i+1][0][rk[st[k]<<2]]=max(dp[i+1][1][rk[st[k]<<2]],dp[i][m][k]);
}
cout << ans << endl;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: