您的位置:首页 > 其它

插头dp模板(简单路径+一条回路+广义路径)

2015-10-04 19:07 411 查看
#include<cstdio>
#include<algorithm>
#include<cstring>
#define Ms(a,x) memset(a,x,sizeof(a))
/*
插头dp模板
1.解决1条简单路径问题
2.本模板使用括号表示法,hash使用链表
4.输入的为地图权值,输出的为一条简单路径可以得到的最大权值(有障碍,路可以不走)
5.记得当状态表示的太大时code的类型要改为longlong
*/
using namespace std;
typedef long long Int;
const int Hashsize=10007;
const int Maxstate=15000;
int n,m;
int Map[12][12];
Int ans;
inline void up(Int &x,Int y)
{
if(y>x)x=y;
}
void input()
{
scanf("%d%d",&n,&m);
ans=0;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
scanf("%d",&Map[i][j]),up(ans,Map[i][j]);
}
inline int get(int code,int y)
{
return code>>2*y&3;
}
inline int shift(int x,int y)
{
return x<<2*y;
}
struct Hash
{
int state[Maxstate],head[Hashsize],nxt[Maxstate];
Int w[Maxstate];
int tot;
void init()
{
Ms(head,-1);
tot=0;
}
void insert(int x,Int y)
{
int t=x%Hashsize;
for(int i=head[t];~i;i=nxt[i])
if(state[i]==x)
{
up(w[i],y);
return;
}
nxt[tot]=head[t];
head[t]=tot;
w[tot]=y;
state[tot++]=x;
}
void pt()//debug专用
{
printf("tot=%d\n",tot);
for(int i=0;i<tot;i++)
{
for(int j=0,t=state[i];j<=m+1;j++,t>>=2)
printf("%3d ",t&3);
printf("w=%lld\n",w[i]);
}puts("");
}
}h[2];
void modify(int &code,int loc,int tar,int dir,int ned)
{
int incode[13],i,t;
for(i=0,t=code;i<=m;i++,t>>=2)
incode[i]=t&3;
int cnt=0;
for(i=loc;;i+=dir)
if(incode[i]==ned)
{
if(!cnt){code+=(tar-get(code,i))*shift(1,i);return;}
cnt--;
}
else if(incode[i]==3-ned)cnt++;
}
void dp(int cs,int x,int y)
{
for(int i=0;i<h[cs].tot;i++)
{
int code=h[cs].state[i];
//printf("%d %d %d\n",code,x,y);
int dep=get(code,m+1);
Int w=h[cs].w[i]+Map[x][y];
if(x&&!y)
{
code-=shift(dep,m+1);
code<<=2;code+=shift(dep,m+1);
}
int left=get(code,y),up=get(code,y+1);
if(!Map[x][y])
{
if(!left&&!up)h[cs^1].insert(code,w);
continue;
}
if(left&&up)
{
code-=shift(left,y)+shift(up,y+1);
if(left==3&&up==3)
{
h[cs^1].insert(code,w);
continue;
}
if(left==3||up==3)
{
int di,ned;
if(left==3)ned=up;
else ned=left;
di=ned==1?1:-1;
modify(code,left==3?y+1:y,3,di,3-ned);//code,loc,tar,dir,ned
h[cs^1].insert(code,w);
continue;
}
if(left==up)
{
modify(code,left==1?y+1:y,left,left==1?1:-1,3-left);
h[cs^1].insert(code,w);
continue;
}
if(left==2&&up==1)
{
h[cs^1].insert(code,w);
continue;
}
continue;
}
if(!left&&!up)
{
if(x<n-1&&y<m-1)
h[cs^1].insert(code+shift(1,y)+shift(2,y+1),w);
if(dep<2)
{
if(x<n-1)h[cs^1].insert(code+shift(3,y)+shift(1,m+1),w);
if(y<m-1)h[cs^1].insert(code+shift(3,y+1)+shift(1,m+1),w);
}
h[cs^1].insert(code,w-Map[x][y]);
continue;
}
if(left&&!up)
{
if(dep<2)
{
int code1=code;
code1+=shift(1,m+1)-shift(left,y);
if(left==1)modify(code1,y,3,1,2);
else if(left==2)modify(code1,y,3,-1,1);
h[cs^1].insert(code1,w);
}
if(x<n-1)h[cs^1].insert(code,w);
if(y<m-1)h[cs^1].insert(code-shift(left,y)+shift(left,y+1),w);
continue;
}
if(!left&&up)
{
if(dep<2)
{
int code1=code;
code1+=shift(1,m+1)-shift(up,y+1);
if(up==1)modify(code1,y+1,3,1,2);
else if(up==2)modify(code1,y+1,3,-1,1);
h[cs^1].insert(code1,w);
}
if(y<m-1)h[cs^1].insert(code,w);
if(x<n-1)h[cs^1].insert(code-shift(up,y+1)+shift(up,y),w);
continue;
}
}
}
void solve()
{
int cs=0;
//int all=0;
h[0].init();
h[0].insert(0,0);
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
{
h[cs^1].init();
dp(cs,i,j);
cs^=1;
//debug专用
//printf("转移完%d %d\n",i,j);
//h[cs].pt();
//    all=max(all,h[cs].tot);
}
for(int i=0;i<h[cs].tot;i++)
up(ans,h[cs].w[i]);
printf("%lld\n",ans);
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
input();
solve();
}
return 0;
}


/*
插头dp模板
1.解决全图为一条回路,有障碍
2.括号匹配:0:无插头,1:左插头,2:右插头
3.极限数据12 12 无障碍:1076226888605605706
*/
#include<bits/stdc++.h>
using namespace std;
const int Hashsize=10007;
typedef long long Int;
int n,m,ex,ey;//ex,ey为最后一个非障碍格
bool Map[12][12];
char s[12];
void input()
{
for(int i=0;i<n;i++)
{
scanf("%s",s);//比如把这句注释了,输入12 12,应该得到1076226888605605706
for(int j=0;j<m;j++)Map[i][j]=s[j]=='#'?1:0;
}
ex=n-1,ey=m-1;
}
struct Hash
{
vector<int>state,nxt;
vector<Int>w;
int head[Hashsize];
int tot;
void init()
{
memset(head,-1,sizeof(head));
tot=0;
state.clear();
nxt.clear();
w.clear();
}
void insert(int x,Int y)
{
int t=x%Hashsize;
for(int i=head[t];i!=-1;i=nxt[i])
{
if(state[i]==x)
{
w[i]+=y;
return;
}
}
nxt.push_back(head[t]);
state.push_back(x);
w.push_back(y);
head[t]=tot++;
}
}h[2];
inline int get(int code,int y)
{
return code>>2*y&3;
}
inline int shift(int x,int y)
{
return x<<2*y;
}
void modify(int &code,int loc,int pace)
{
int ned=pace>0?2:1;
int incode[13];
for(int i=0,t=code;i<=m;i++,t>>=2)
incode[i]=t&3;
int cnt=0;
for(int i=loc;;i+=pace)
{
if(incode[i]==ned)
{
if(!cnt){code-=pace*shift(1,i);return;}
cnt--;
}
else if(incode[i])cnt++;
}
}
void dp(int cs,int x,int y)//记得设置ex,ey
{
if(Map[x][y])
{
for(int i=0;i<h[cs].tot;i++)
{
int code=h[cs].state[i];
if(x&&!y)code<<=2;
int left=get(code,y),up=get(code,y+1);
if(!left&&!up)h[cs^1].insert(code,h[cs].w[i]);
}
return;
}
for(int i=0;i<h[cs].tot;i++)
{
int code=h[cs].state[i];
Int w=h[cs].w[i];
if(x&&!y)code<<=2;
int left=get(code,y),up=get(code,y+1);
if(left&&up)
{
code-=shift(left,y)+shift(up,y+1);
if(left!=up)
{
if((x==ex&&y==ey)||left==2)
h[cs^1].insert(code,w);
continue;
}
if(left==1)
{
modify(code,y+2,1);
h[cs^1].insert(code,w);
continue;
}
if(left==2)
{
modify(code,y-1,-1);
h[cs^1].insert(code,w);
continue;
}
}
if(left&&!up)
{
if(x<n-1)h[cs^1].insert(code,w);
if(y<m-1)h[cs^1].insert(code-shift(left,y)+shift(left,y+1),w);
continue;
}
if(up&&!left)
{
if(y<m-1)h[cs^1].insert(code,w);
if(x<n-1)h[cs^1].insert(code-shift(up,y+1)+shift(up,y),w);
}
if(!left&&!up&&x<n-1&&y<m-1)
h[cs^1].insert(code+shift(1,y)+shift(2,y+1),w);
}
}
void solve()
{
int cs=0;
h[0].init();
h[0].insert(0,1);
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
printf("i=%d j=%d\n",i,j);
printf("tot=%d\n",h[cs].tot);
h[cs^1].init();
dp(cs,i,j);
cs^=1;
}
}
Int ans=0;
for(int i=0;i<h[cs].tot;i++)
ans+=h[cs].w[i];
printf("%lld\n",ans);
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
input();
solve();
}
}


#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define Ms(a,x) memset(a,x,sizeof(a))
using namespace std;
typedef long long Int;
const int Hashsize=10007,Maxstate=15000;
char Map[9][9];
char ch[]={'o','#'};
int pre[9][9][Maxstate];
int pe[9][9][Maxstate];
int n,m;
/*
原题 uva10572 广义路径
题意:棋盘只能涂黑白,黑白各自联通,不能有2*2的方块涂有相同的颜色,要求输出方案数和其中一种方案
*/
inline int shift(int x,int y)
{
return x<<y;
}
inline int get(int x,int y)
{
return x>>y&1;
}
struct Hash
{
int head[Hashsize];
int nxt[Maxstate],state[Maxstate],col[Maxstate];
Int w[Maxstate];
int tot;
void init()
{
tot=0;
Ms(head,-1);
}
void insert(int st,int cl,Int ww,int x,int y,int pst,int cs)
{
int t=((st<<5)+cl)%Hashsize;
for(int i=head[t];~i;i=nxt[i])
if(state[i]==st&&col[i]==cl)
{
w[i]+=ww;
pre[x][y][i]=pst;
pe[x][y][i]=cs;
return;
}
nxt[tot]=head[t];
head[t]=tot;
state[tot]=st,col[tot]=cl,w[tot]=ww;
pe[x][y][tot]=cs;
pre[x][y][tot++]=pst;
}
//for debug
void pt()
{
printf("tot=%d\n",tot);
for(int i=0;i<tot;i++)
{
printf("state= ");
for(int j=0,k=state[i];j<m;j++,k>>=3)
printf("%3d",k&7);
puts("");
printf("col= ");
for(int j=0,k=col[i];j<m+3;j++,k>>=1)
printf("%3d",k&1);
puts("");
printf("w=%lld\n",w[i]);
puts("");
}
}
}h[2];
int code[10];
void decode(int cd)
{
for(int i=0;i<m;i++,cd>>=3)
code[i]=cd&7;
}
int encode()
{
int ref[10],cnt=0;
Ms(ref,-1);
for(int i=0;i<m;i++)
{
if(ref[code[i]]<0)
ref[code[i]]=cnt++;
code[i]=ref[code[i]];
}
int ret=0;
for(int i=m-1;i>=0;i--)
ret=(ret<<3)+code[i];
return ret;
}
bool check(int y,int st)
{
for(int i=st;i<m;i++)
if(i!=y&&code[i]==code[y])
return true;
return false;
}
void modify(int loc,int x)
{
int t=code[loc];
for(int i=0;i<m;i++)
if(code[i]==t)
code[i]=x;
}
void dp(int cs,int x,int y,int cl)
{
if(Map[x][y]!='.'&&Map[x][y]!=ch[cl])return;
//col的第0-m位表示格子的颜色,m+1-m+2表示是否只能使用一种颜色10只能用白色,11只能用黑色
for(int i=0;i<h[cs].tot;i++)
{
int col=h[cs].col[i],st=h[cs].state[i];
int last=col>>(m+1);
col-=last<<(m+1);
if(x&&!y)
{
col=col&shift(1,m)-1;
col<<=1;
}
//ul,ur,dl分别表示左上、右上、左下的格子的颜色
int ul=0,ur=0,dl=0;
if(x){ul=get(col,y);ur=get(col,y+1);}
if(y)dl=get(col,y-1);
//这四个格子颜色不能全部相同
if(x&&y&&dl==ul&&ul==ur&&ul==cl)
continue;
//如果后面的格子只能使用一种颜色但与当前使用的不同,则不合法
if(last&&(last&1)!=cl)continue;
col+=(cl-ul)*shift(1,y);
//解码
decode(st);
//考虑一些联通分量消失的格子,如果他们所处的联通分量消失了,则后面只能涂一种颜色
bool flag=false;
if(x&&ur!=cl&&!check(y,x==n-1?y+1:0))
{
if(last)continue;
flag=true;
}
if(x==n-1&&y&&!last&&dl!=cl&&!check(y-1,y+1))
{
if(last)continue;
if(flag&&code[y-1]!=code[y])continue;
flag=true;
}
if(flag)last=2+cl;
col+=last<<(m+1);
//重新编码+最小表示
if(y&&cl==dl)modify(y-1,9);
if(x&&ur==cl)modify(y,9);
code[y]=9;
h[cs^1].insert(encode(),col,h[cs].w[i],x,y,i,cl);
}
}
vector<int>bef;
void solve()
{
int cs=0;
h[cs].init();
h[cs].insert(0,0,1,0,0,0,0);

for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
{
h[cs^1].init();
for(int k=0;k<2;k++)
dp(cs,i,j,k);
cs^=1;
//printf("转移完%d %d\n",i,j);h[cs].pt();
}
Int ans=0;
int last=-1;
bef.clear();
for(int i=0;i<h[cs].tot;i++)
{
if(h[cs].w[i])
ans+=h[cs].w[i],last=i,bef.push_back(i);
}
if(!ans)puts("0\n");
else
{//for debug
/*for(int k=0;k<bef.size();k++)
{
int st=bef[k];
for(int i=n-1;i>=0;i--)
for(int j=m-1;j>=0;st=pre[i][j][st],j--)
Map[i][j]=pe[i][j][st]?'#':'o';
for(int i=0;i<n;i++)
printf("%s\n",Map[i]);
puts("");
}*/
printf("%lld\n",ans);
for(int i=n-1;i>=0;i--)
for(int j=m-1;j>=0;last=pre[i][j][last],j--)
Map[i][j]=pe[i][j][last]?'#':'o';
for(int i=0;i<n;i++)
printf("%s\n",Map[i]);
puts("");
}
}
void input()
{
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)
scanf("%s",Map[i]);
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
input();
solve();
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: