插头dp
来源:互联网 发布:2016淘宝广告位价格 编辑:程序博客网 时间:2024/04/28 05:31
最近学习了基于连通性的动态规划,也就是插头dp,刷了一些入门题。
插头dp主要解决的问题是,给定矩阵,矩阵中有些点不能到达,有些点可以到达,问经过所有可达到的点,且每个点只经过一次的回路有多少种。
学习资料有很多,相关的博客也不少,罗列一些:
cdq论文
cyendra博客
个人认为上面那篇博客讲的十分详细,值得一看。
——————————————-分割线—————————————————
插头dp的一些题,以下所用的ac代码用的全是kuangbin巨巨的模板。
HDU 1693
这是一道比较典型的题,给出矩阵,矩阵中有可达点和不可达点,求经过所有可达点一次的回路的方案数,允许一个方案中存在多条回路。既然允许存在多条回路,那么可以不用给联通块标号,code数组中只给出连通性即可。
#include<stdio.h>#include<string.h>#include<stdlib.h>#include<iostream>#include<algorithm>#define LL long longusing namespace std;const int hash_mod=100007;const int state_size=1e6+50;const int maxc=15;int code[maxc], G[maxc][maxc];struct HASHMAP{ int head[hash_mod], state[state_size], next[state_size], st_size; LL cnt[state_size]; void init(){ st_size=0; memset(head, -1, sizeof head); } void push(int st,LL c){ int i, h=st%hash_mod; for(i=head[h];i!=-1;i=next[i]) if(st==state[i]){ cnt[i]+=c; return; } cnt[st_size]=c; state[st_size]=st; next[st_size]=st; head[st]=st_size++; }};HASHMAP hm[2];int n, m, cas;void init(){ scanf("%d%d",&n, &m); memset(G, 0, sizeof G); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++) scanf("%d",&G[i][j]); }}int encode(int code[], int m){ int ret=0; for(int i=0;i<=m;i++) if(code[i]) ret|=(1<<i); return ret;}void decode(int code[], int m, int st){ for(int i=0;i<=m;i++) code[i]=st&(1<<i);}void shift(int code[], int m){ for(int i=m;i>0;i--) code[i]=code[i-1]; code[0]=0;}void dpblank(int r,int c,int cur){ int left, up; for(int i=0;i<hm[cur].st_size;i++){ decode(code, m, hm[cur].state[i]); left=code[c-1]; up=code[c]; if(left&&up){// 11 code[c-1]=code[c]=0;//influence on next row if(c==m) shift(code, m); hm[cur^1].push(encode(code, m), hm[cur].cnt[i]); }else if(left||up){ if(G[r+1][c]){ code[c-1]=1; code[c]=0; if(c==m) shift(code, m); hm[cur^1].push(encode(code, m), hm[cur].cnt[i]); } if(G[r][c+1]){ code[c-1]=0; code[c]=1; hm[cur^1].push(encode(code, m), hm[cur].cnt[i]); } }else{ if(G[r+1][c]&&G[r][c+1]){ code[c-1]=code[c]=1; hm[cur^1].push(encode(code, m), hm[cur].cnt[i]); } } }}void dpblock(int r,int c,int cur){ for(int i=0;i<hm[cur].st_size;i++){ decode(code, m, hm[cur].state[i]); code[c-1]=code[c]=0; if(c==m) shift(code, m); hm[cur^1].push(encode(code, m), hm[cur].cnt[i]); }}void solve(){ int cur=0; hm[cur].init(); hm[cur].push(0, 1); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ hm[cur^1].init(); if(G[i][j]==1){ dpblank(i, j, cur); }else{ dpblock(i, j, cur); } cur^=1; } LL ans=0; for(int i=0;i<hm[cur].st_size;i++) ans+=hm[cur].cnt[i]; printf("Case %d: There are %lld ways to eat the trees.\n", ++cas, ans);}int main(){ int T; scanf("%d",&T); while(T--){ init(); solve(); } return 0;}
URAL 1519
给定矩阵,其中包含可达点和不可达点,求经过所有可达点的回路的方案数。与上一题的区别是,这里必须一条回路走完所有点。
要求一条回路走完,那么必须要给联通块标号,并在code数组中给出连通性及标号,避免在没有走完所有点之前就已经形成了回路。
#include<stdio.h>#include<string.h>#include<stdlib.h>#include<iostream>#include<algorithm>#define LL long longusing namespace std;const int hash_mod=100007;const int state_size=1e6+50;const int maxc=15;int id[maxc], code[maxc], G[maxc][maxc];struct HASHMAP{ int head[hash_mod], next[state_size], st_size; LL state[state_size]; LL cnt[state_size]; void init(){ st_size=0; memset(head, -1, sizeof head); } void push(LL st,LL c){ int i, h=st%hash_mod; for(i=head[h];i!=-1;i=next[i]) if(st==state[i]){ cnt[i]+=c; return; } cnt[st_size]=c; state[st_size]=st; next[st_size]=head[h]; head[h]=st_size++; }};HASHMAP hm[2];int n, m, cas;int tx, ty;void init(){ char s[maxc]; //scanf("%d%d",&n, &m); memset(G, 0, sizeof G); for(int i=1;i<=n;i++){ scanf("%s", s+1); for(int j=1;j<=m;j++) if(s[j]=='.'){ G[i][j]=1; tx=i, ty=j; } else G[i][j]=0; }}LL encode(int code[], int m){ LL ret=0; int cnt=0; memset(id, -1, sizeof id); id[0]=0; for(int i=0;i<=m;i++){ if(id[code[i]]==-1) id[code[i]]=++cnt; code[i]=id[code[i]]; ret<<=3; ret|=code[i]; } return ret;}void decode(int code[], int m, LL st){ for(int i=m;i>=0;i--){ code[i]=st&7; st>>=3; }}void shift(int code[], int m){ for(int i=m;i>0;i--) code[i]=code[i-1]; code[0]=0;}void dpblank(int r,int c,int cur){ int left, up; for(int i=0;i<hm[cur].st_size;i++){ decode(code, m, hm[cur].state[i]); left=code[c-1]; up=code[c]; if(left&&up){// 11 if(left==up){//in the same cc if(r==tx&&c==ty){//is the last grid code[c-1]=code[c]=0;//no right and down plug if(c==m) shift(code, m); hm[cur^1].push(encode(code, m), hm[cur].cnt[i]); } }else{//not in the same cc code[c-1]=code[c]=0; for(int i=0;i<=m;i++)//combine the two cc and update code if(code[i]==left) code[i]=up; if(c==m) shift(code, m); hm[cur^1].push(encode(code, m), hm[cur].cnt[i]); } }else if(left||up){ int tmp; if(left) tmp=left; else tmp=up; if(G[r+1][c]){ code[c-1]=tmp; code[c]=0; if(c==m) shift(code, m); hm[cur^1].push(encode(code, m), hm[cur].cnt[i]); } if(G[r][c+1]){ code[c-1]=0; code[c]=tmp; hm[cur^1].push(encode(code, m), hm[cur].cnt[i]); } }else{ if(G[r+1][c]&&G[r][c+1]){ code[c-1]=code[c]=13;//assign a huge value hm[cur^1].push(encode(code, m), hm[cur].cnt[i]); } } }}void dpblock(int r,int c,int cur){ for(int i=0;i<hm[cur].st_size;i++){ decode(code, m, hm[cur].state[i]); code[c-1]=code[c]=0; if(c==m) shift(code, m); hm[cur^1].push(encode(code, m), hm[cur].cnt[i]); }}void solve(){ int cur=0; hm[cur].init(); hm[cur].push(0, 1); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ hm[cur^1].init(); if(G[i][j]==1){ dpblank(i, j, cur); }else{ dpblock(i, j, cur); } cur^=1; } LL ans=0; for(int i=0;i<hm[cur].st_size;i++) ans+=hm[cur].cnt[i]; printf("%lld\n", ans); //printf("Case %d: There are %lld ways to eat the trees.\n", ++cas, ans);}int main(){ int T; //scanf("%d",&T); //while(T--){ while(~scanf("%d%d",&n, &m)){ init(); solve(); } //} return 0;}
FZU 1977
给定矩阵,其中有不可达点,必达点(回路中必须经过的点),选达点(回路中可以经过也可以不经过的点),求经过所有必达点的回路的方案数,方案中只能有一条回路。
这里加入了选达点,这意味着我们在考虑一个点时,如果它没有与之前的点联通,我们不仅需要考虑它同时向下和向右伸出插头,还要考虑它没有任何插头的情况并加入到hash map中。
输出用__int64,long long会WA。
#include<stdio.h>#include<string.h>#include<stdlib.h>#include<iostream>#include<algorithm>#include<limits.h>#define LL __int64using namespace std;const int hash_mod=100007;const int state_size=5e5+50;const int maxc=15;int id[maxc], code[maxc], G[maxc][maxc];struct HASHMAP{ int head[hash_mod], next[state_size], st_size; LL state[state_size]; LL cnt[state_size]; void init(){ st_size=0; memset(head, -1, sizeof head); } void push(LL st,LL c){ int i, h=st%hash_mod; for(i=head[h];i!=-1;i=next[i]) if(st==state[i]){ cnt[i]+=c; return; } cnt[st_size]=c; state[st_size]=st; next[st_size]=head[h]; head[h]=st_size++; }};HASHMAP hm[2];int n, m, cas;int isend;int tx, ty;void init(){ char s[maxc]; scanf("%d%d",&n, &m); memset(G, 0, sizeof G); for(int i=1;i<=n;i++){ scanf("%s", s+1); for(int j=1;j<=m;j++) if(s[j]=='X'){ G[i][j]=0; }else if(s[j]=='O'){ G[i][j]=1; tx=i, ty=j; }else{ G[i][j]=2; } }}LL encode(int code[], int m){ LL ret=0; int cnt=0; memset(id, -1, sizeof id); id[0]=0; for(int i=0;i<=m;i++){ if(id[code[i]]==-1) id[code[i]]=++cnt; code[i]=id[code[i]]; ret<<=3; ret|=code[i]; } ret<<=1; ret|=isend; return ret;}void decode(int code[], int m, LL st){ isend=st&1; st>>=1; for(int i=m;i>=0;i--){ code[i]=st&7; st>>=3; }}void shift(int code[], int m){ for(int i=m;i>0;i--) code[i]=code[i-1]; code[0]=0;}void dpblank(int r,int c,int cur){ int left, up; for(int i=0;i<hm[cur].st_size;i++){ decode(code, m, hm[cur].state[i]); left=code[c-1]; up=code[c]; if(isend){ if(left||up||G[r][c]==1) continue; } if(left&&up){// 11 if(left==up){//in the same cc code[c-1]=code[c]=0;//no right and down plug isend=1; //if(c==m) shift(code, m); hm[cur^1].push(encode(code, c==m?m-1:m), hm[cur].cnt[i]); }else{//not in the same cc code[c-1]=code[c]=0; for(int i=0;i<=m;i++)//combine the two cc and update code if(code[i]==left) code[i]=up; //if(c==m) shift(code, m); hm[cur^1].push(encode(code, c==m?m-1:m), hm[cur].cnt[i]); } }else if(left||up){ int tmp; if(left) tmp=left; else tmp=up; if(G[r+1][c]){ code[c-1]=tmp; code[c]=0; //if(c==m) shift(code, m); hm[cur^1].push(encode(code, c==m?m-1:m), hm[cur].cnt[i]); } if(G[r][c+1]){ code[c-1]=0; code[c]=tmp; hm[cur^1].push(encode(code, c==m?m-1:m), hm[cur].cnt[i]); } }else{ if(G[r+1][c]&&G[r][c+1]){ code[c-1]=code[c]=13;//assign a huge value hm[cur^1].push(encode(code, m), hm[cur].cnt[i]); } if(G[r][c]==2){ code[c-1]=code[c]=0; //if(c==m) shift(code, m); hm[cur^1].push(encode(code, c==m?m-1:m), hm[cur].cnt[i]); } } }}void dpblock(int r,int c,int cur){ for(int i=0;i<hm[cur].st_size;i++){ decode(code, m, hm[cur].state[i]); code[c-1]=code[c]=0; //if(c==m) shift(code, m); hm[cur^1].push(encode(code, c==m?m-1:m), hm[cur].cnt[i]); }}void solve(){ int cur=0; LL ans=0; hm[cur].init(); hm[cur].push(0, 1); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ hm[cur^1].init(); if(G[i][j]){ dpblank(i, j, cur); }else{ dpblock(i, j, cur); } cur^=1; } for(int i=0;i<hm[cur].st_size;i++) ans+=hm[cur].cnt[i]; //printf("%lld\n", ans); printf("Case %d: %I64d\n", ++cas, ans);}int main(){ int T; scanf("%d",&T); while(T--){ //while(~scanf("%d%d",&n, &m)){ init(); solve(); } //} return 0;}
HDU 1964
这道题是求一条权值最大的回路。把hash map中的push函数中的cnt加操作改为取大值即可。
#include<stdio.h>#include<string.h>#include<stdlib.h>#include<iostream>#include<algorithm>#define LL long long#define UP 0#define RIGHT 1#define DOWN 2#define LEFT 3using namespace std;const int hash_mod=100007;const int max_state=1e6+50;const int maxc=15;struct HASHMAP{ int head[hash_mod], next[max_state]; LL state[max_state]; int size; int cost[max_state]; void init(){ size=0; memset(head, -1, sizeof(head)); } void push(LL x,int c){ int i, h=x%hash_mod; for(i=head[h];i!=-1;i=next[i]) if(state[i]==x){ cost[i]=min(cost[i], c); return; } state[size]=x; cost[size]=c; next[size]=head[h]; head[h]=size++; }};HASHMAP hm[2];int n, m;int id[maxc];int code[maxc];char s[maxc*2][maxc*2];void decode(int code[],int m,LL st){ for(int i=m;i>=0;i--){ code[i]=st&7; st>>=3; }}LL encode(int code[], int m){ LL ret=0; int cnt=0; memset(id, -1, sizeof id); id[0]=0; for(int i=0;i<=m;i++){ if(id[code[i]]==-1) id[code[i]]=++cnt; code[i]=id[code[i]]; ret<<=3; ret|=code[i]; } return ret;}void shift(int code[],int m){ for(int i=m;i>0;i--) code[i]=code[i-1]; code[0]=0;}int getcost(int r,int c,int d){ int x=2*r-1, y=2*c-1; int ret=0; if(d==UP&&s[x-1][y]!='#') ret+=s[x-1][y]-'0'; if(d==DOWN&&s[x+1][y]!='#') ret+=s[x+1][y]-'0'; if(d==LEFT&&s[x][y-1]!='#') ret+=s[x][y-1]-'0'; if(d==RIGHT&&s[x][y+1]!='#') ret+=s[x][y+1]-'0'; return ret;}void dpblank(int r,int c,int cur){ int left, up; for(int i=0;i<hm[cur].size;i++){ LL st=hm[cur].state[i]; int cost=hm[cur].cost[i]; decode(code, m, st); left=code[c-1]; up=code[c]; if(left&&up){ if(left==up){//in the same cc if(r==n&&c==m){ code[c-1]=code[c]=0; if(c==m) shift(code, m); hm[cur^1].push(encode(code, m), cost); } }else{//not in the same cc code[c-1]=code[c]=0; for(int i=0;i<=m;i++)//make then in the same cc if(code[i]==left) code[i]=up; if(c==m) shift(code, m); hm[cur^1].push(encode(code, m), cost); } }else if(left||up){ int tmp; if(left) tmp=left; else tmp=up; if(c+1<=m){ code[c-1]=0; code[c]=tmp; hm[cur^1].push(encode(code, m), cost+getcost(r, c, RIGHT)); } if(r+1<=n){ code[c-1]=tmp; code[c]=0; if(c==m) shift(code, m); hm[cur^1].push(encode(code, m), cost+getcost(r, c, DOWN)); } }else{ if(r+1<=n&&c+1<=m){ code[c-1]=code[c]=13; hm[cur^1].push(encode(code, m), cost+getcost(r, c, RIGHT)+getcost(r, c, DOWN)); } } }}void dpblock(int r,int c,int cur){ for(int i=0;i<hm[cur].size;i++){ LL st=hm[cur].state[i]; LL cost=hm[cur].cost[i]; decode(code, m, st); code[c-1]=code[c]=0; hm[cur^1].push(encode(code, m), cost); }}void init(){ scanf("%d%d",&n, &m); getchar(); for(int i=0;i<2*n+1;i++) gets(s[i]);}void solve(){ int cur=0; hm[cur].init(); hm[cur].push(0, 0); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ hm[cur^1].init(); dpblank(i, j, cur); cur^=1; } } int ans=0x3f3f3f3f; for(int i=0;i<hm[cur].size;i++) ans=min(ans, hm[cur].cost[i]); printf("%d\n", ans);}int main(){ int T; scanf("%d", &T); while(T--){ init(); solve(); } return 0;}
HDU 3377
找一条从左上角到右下角的权值和最大的路径。
把起点和终点特殊处理即可,因为他们只有一个插头,其他点都有两个插头。
#include<stdio.h>#include<string.h>#include<stdlib.h>#include<iostream>#include<algorithm>#define LL long long#define UP 0#define RIGHT 1#define DOWN 2#define LEFT 3using namespace std;const int hash_mod=100007;const int max_state=1e6+50;const int maxc=15;struct HASHMAP{ int head[hash_mod], next[max_state]; LL state[max_state]; int size; int cost[max_state]; void init(){ size=0; memset(head, -1, sizeof(head)); } void push(LL x,int c){ int i, h=x%hash_mod; for(i=head[h];i!=-1;i=next[i]) if(state[i]==x){ cost[i]=max(cost[i], c); return; } state[size]=x; cost[size]=c; next[size]=head[h]; head[h]=size++; }};HASHMAP hm[2];int n, m, cas;int id[maxc];int code[maxc];int G[maxc][maxc];void decode(int code[],int m,LL st){ for(int i=m;i>=0;i--){ code[i]=st&7; st>>=3; }}LL encode(int code[], int m){ LL ret=0; int cnt=0; memset(id, -1, sizeof id); id[0]=0; for(int i=0;i<=m;i++){ if(id[code[i]]==-1) id[code[i]]=++cnt; code[i]=id[code[i]]; ret<<=3; ret|=code[i]; } return ret;}void shift(int code[],int m){ for(int i=m;i>0;i--) code[i]=code[i-1]; code[0]=0;}int getcost(int r,int c,int d){ int x=r, y=c; int ret=0; if(d==UP&&x-1>=1) ret+=G[x-1][y]; if(d==DOWN&&x+1<=n) ret+=G[x+1][y]; if(d==LEFT&&y-1>=1) ret+=G[x][y-1]; if(d==RIGHT&&y+1<=m) ret+=G[x][y+1]; return ret;}void dpblank(int r,int c,int cur){ int left, up; for(int i=0;i<hm[cur].size;i++){ LL st=hm[cur].state[i]; int cost=hm[cur].cost[i]; decode(code, m, st); left=code[c-1]; up=code[c]; if(left&&up){ if(r==n&&c==m) continue; if(left==up){//in the same cc continue; }else{//not in the same cc code[c-1]=code[c]=0; for(int i=0;i<=m;i++)//make then in the same cc if(code[i]==left) code[i]=up; if(c==m) shift(code, m); hm[cur^1].push(encode(code, m), cost+G[r][c]); } }else if(left||up){ int tmp; if(left) tmp=left; else tmp=up; if(r==n&&c==m){ code[c-1]=code[c]=0; shift(code, m); hm[cur^1].push(encode(code, m), cost+G[r][c]); continue; puts("Infinity"); } if(c+1<=m){ code[c-1]=0; code[c]=tmp; hm[cur^1].push(encode(code, m), cost+G[r][c]); } if(r+1<=n){ code[c-1]=tmp; code[c]=0; if(c==m) shift(code, m); hm[cur^1].push(encode(code, m), cost+G[r][c]); } }else{ if(r==n&&c==m) continue; if(r+1<=n&&c+1<=m){ code[c-1]=code[c]=13; hm[cur^1].push(encode(code, m), cost+G[r][c]); } code[c-1]=code[c]=0; if(c==m) shift(code, m); hm[cur^1].push(encode(code, m), cost); } }}void dpblock(int r,int c,int cur){ for(int i=0;i<hm[cur].size;i++){ LL st=hm[cur].state[i]; LL cost=hm[cur].cost[i]; decode(code, m, st); code[c-1]=code[c]=0; hm[cur^1].push(encode(code, m), cost); }}void init(){ //scanf("%d%d",&n, &m); getchar(); //for(int i=0;i<2*n+1;i++) // gets(s[i]); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d", &G[i][j]);}void solve(){ if(n==1&&m==1){ printf("Case %d: %d\n",++cas, G[1][1]); return; } int ans=-0x3f3f3f3f; int cur=0; memset(code, 0, sizeof(code)); hm[cur].init(); if(2<=m){ code[0]=0, code[1]=1; if(m==1) shift(code, m); hm[cur].push(encode(code, m), G[1][1]); } if(2<=n){ code[0]=1, code[1]=0; if(m==1) shift(code, m); hm[cur].push(encode(code, m), G[1][1]); } for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++) if(i+j>2){ hm[cur^1].init(); dpblank(i, j, cur); cur^=1; } } for(int i=0;i<hm[cur].size;i++){ ans=max(ans, hm[cur].cost[i]); } printf("Case %d: %d\n",++cas, ans);}int main(){ int T; //scanf("%d", &T); while(~scanf("%d%d",&n, &m)){ init(); solve(); } return 0;}
POJ 1739
求左下角,注意是左下角,到右下角的经过所有可达点路径的条数。
在原图末尾再添两行,并把其中第一行的中间设为不可达,其他均可达,然后求经过所有可达点的回路数即可。
即在末尾加
.*****.(m-2个*)
…….(m个.)
#include<stdio.h>#include<string.h>#include<stdlib.h>#include<iostream>#include<algorithm>#define LL long long#define UP 0#define RIGHT 1#define DOWN 2#define LEFT 3using namespace std;const int hash_mod=100007;const int max_state=1e6+50;const int maxc=15;struct HASHMAP{ int head[hash_mod], next[max_state]; LL state[max_state]; int size; LL cost[max_state]; void init(){ size=0; memset(head, -1, sizeof(head)); } void push(LL x,LL c){ int i, h=x%hash_mod; for(i=head[h];i!=-1;i=next[i]) if(state[i]==x){ cost[i]+=c; return; } state[size]=x; cost[size]=c; next[size]=head[h]; head[h]=size++; }};HASHMAP hm[2];int n, m, cas;int id[maxc];int code[maxc];int G[maxc][maxc];char s[maxc][maxc];void decode(int code[],int m,LL st){ for(int i=m;i>=0;i--){ code[i]=st&7; st>>=3; }}LL encode(int code[], int m){ LL ret=0; int cnt=0; memset(id, -1, sizeof id); id[0]=0; for(int i=0;i<=m;i++){ if(id[code[i]]==-1) id[code[i]]=++cnt; code[i]=id[code[i]]; ret<<=3; ret|=code[i]; } return ret;}void shift(int code[],int m){ for(int i=m;i>0;i--) code[i]=code[i-1]; code[0]=0;}int getcost(int r,int c,int d){ int x=r, y=c; int ret=0; if(d==UP&&x-1>=1) ret+=G[x-1][y]; if(d==DOWN&&x+1<=n) ret+=G[x+1][y]; if(d==LEFT&&y-1>=1) ret+=G[x][y-1]; if(d==RIGHT&&y+1<=m) ret+=G[x][y+1]; return ret;}void dpblank(int r,int c,int cur){ int left, up; for(int i=0;i<hm[cur].size;i++){ LL st=hm[cur].state[i]; LL cost=hm[cur].cost[i]; decode(code, m, st); left=code[c-1]; up=code[c]; if(left&&up){ if(left==up){//in the same cc if(r==n&&c==m){ code[c-1]=code[c]=0; shift(code, m); hm[cur^1].push(encode(code, m), cost); } }else{//not in the same cc code[c-1]=code[c]=0; for(int i=0;i<=m;i++)//make then in the same cc if(code[i]==left) code[i]=up; if(c==m) shift(code, m); hm[cur^1].push(encode(code, m), cost); } }else if(left||up){ int tmp; if(left) tmp=left; else tmp=up; if(G[r][c+1]){ code[c-1]=0; code[c]=tmp; hm[cur^1].push(encode(code, m), cost); } if(G[r+1][c]){ code[c-1]=tmp; code[c]=0; if(c==m) shift(code, m); hm[cur^1].push(encode(code, m), cost); } }else{ if(G[r+1][c]&&G[r][c+1]){ code[c-1]=code[c]=13; hm[cur^1].push(encode(code, m), cost); } } }}void dpblock(int r,int c,int cur){ for(int i=0;i<hm[cur].size;i++){ LL st=hm[cur].state[i]; LL cost=hm[cur].cost[i]; decode(code, m, st); code[c-1]=code[c]=0; if(c==m) shift(code, m); hm[cur^1].push(encode(code, m), cost); }}void init(){ //scanf("%d%d",&n, &m); getchar(); //for(int i=0;i<2*n+1;i++) // gets(s[i]); for(int i=1;i<=n;i++) scanf("%s", s[i]+1); memset(G, 0, sizeof G); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) G[i][j]=s[i][j]=='.'; G[n+1][1]=1; G[n+1][m]=1; for(int j=1;j<=m;j++) G[n+2][j]=1; n+=2;}void solve(){ int cur=0; hm[cur].init(); hm[cur].push(0, 1); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ hm[cur^1].init(); if(G[i][j]) dpblank(i, j, cur); else dpblock(i, j, cur); cur^=1; } } LL ans=0; for(int i=0;i<hm[cur].size;i++) ans+=hm[cur].cost[i]; //printf("Case %d: %d\n",++cas, ans); printf("%lld\n", ans);}int main(){ int T; //scanf("%d", &T); while(~scanf("%d%d",&n, &m)){ if(n==0&&m==0) break; init(); solve(); } return 0;}
POJ 3133
2与2通过一条路径相连,3与3通过一条路径相连,并且这两条路径不相交,求路径权值和最小值。
显然在这里联通块只有两个,2所在的和3所在的,再加上处理路径时的方法,路径端点即2和3所在的位置只往外伸出一个插头即可。
#include<math.h>#include<stdio.h>#include<string.h>#include<stdlib.h>#include<iostream>#define LL long longusing namespace std;const int max_state=1e6+50;const int hash_mod=1e5+7;const int maxc=15;const int Inf=0x3f3f3f3f;struct HASHMAP{ LL state[max_state], cnt[max_state]; int head[hash_mod], next[max_state]; int size; void init(){ size=0; memset(head, -1, sizeof head); } void push(LL x,LL c){ int i, h=x%hash_mod; for(i=head[h];i!=-1;i=next[i]) if(state[i]==x){ cnt[i]=min(cnt[i], c); return; } state[size]=x; cnt[size]=c; next[size]=head[h]; head[h]=size++; }};HASHMAP hm[2];int n, m;int id[maxc], code[maxc];int G[maxc][maxc];void decode(int code[], int m, LL st){ for(int i=m;i>=0;i--){ code[i]=st&7; st>>=3; }}LL encode(int code[], int m){ LL ret=0; int cnt=0; memset(id, -1, sizeof id); id[0]=0; for(int i=0;i<=m;i++){ //if(id[code[i]]==-1) id[code[i]]=++cnt; //code[i]=id[code[i]]; ret<<=3; ret|=code[i]; } return ret;}void shift(int code[], int m){ for(int i=m;i>0;i--) code[i]=code[i-1]; code[0]=0;}bool can(int x,int y){ return x==1||x==y;}void dpblank(int r, int c, int cur){ int left, up; for(int i=0;i<hm[cur].size;i++){ LL st=hm[cur].state[i]; LL cnt=hm[cur].cnt[i]; decode(code, m, st); left=code[c-1]; up=code[c]; if(left&&up){ if(left==up){ code[c-1]=code[c]=0; if(c==m) shift(code, m); hm[cur^1].push(encode(code, m), cnt+1); } }else if(left||up){ int tmp; if(left) tmp=left; else tmp=up; if(can(G[r][c+1],tmp)){ code[c-1]=0; code[c]=tmp; hm[cur^1].push(encode(code, m), cnt+1); } if(can(G[r+1][c], tmp)){ code[c-1]=tmp; code[c]=0; if(c==m) shift(code, m); hm[cur^1].push(encode(code, m), cnt+1); } }else{ if(can(G[r][c+1],2)&&can(G[r+1][c],2)){ code[c-1]=code[c]=2; hm[cur^1].push(encode(code, m), cnt+1); } if(can(G[r][c+1],3)&&can(G[r+1][c],3)){ code[c-1]=code[c]=3; hm[cur^1].push(encode(code, m), cnt+1); } code[c-1]=code[c]=0; if(c==m) shift(code, m); hm[cur^1].push(encode(code, m), cnt); } }}void dpblock(int r,int c,int cur){ for(int i=0;i<hm[cur].size;i++){ LL st=hm[cur].state[i]; LL cnt=hm[cur].cnt[i]; decode(code, m, st); code[c-1]=code[c]=0; if(c==m) shift(code, m); hm[cur^1].push(encode(code, m), cnt); }}void dplimit(int r,int c,int cur){ int left, up; for(int i=0;i<hm[cur].size;i++){ LL st=hm[cur].state[i]; LL cnt=hm[cur].cnt[i]; decode(code, m, st); left=code[c-1]; up=code[c]; if(left&&up){ continue; }else if(left||up){ int tmp; if(left) tmp=left; else tmp=up; if(G[r][c]==tmp){ code[c-1]=code[c]=0; if(c==m) shift(code, m); hm[cur^1].push(encode(code, m), cnt+1); } }else{ if(can(G[r][c+1], G[r][c])){ code[c-1]=0; code[c]=G[r][c]; hm[cur^1].push(encode(code, m), cnt+1); } if(can(G[r+1][c], G[r][c])){ code[c-1]=G[r][c]; code[c]=0; if(c==m) shift(code, m); hm[cur^1].push(encode(code, m), cnt+1); } } }}void init(){ memset(G, 0, sizeof G); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ scanf("%d", &G[i][j]); if(G[i][j]==1) G[i][j]=0; else if(G[i][j]==0) G[i][j]=1; }}void solve(){ int cur=0; hm[cur].init(); hm[cur].push(0, 0); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ hm[cur^1].init(); if(G[i][j]==2||G[i][j]==3){ dplimit(i, j, cur); }else if(G[i][j]){ dpblank(i, j, cur); }else{ dpblock(i, j, cur); } cur^=1;// for(int k=0;k<hm[cur].size;k++){// decode(code, m, hm[cur].state[k]);// printf("row=%d line=%d\n", i, j);// for(int l=0;l<=m;l++)// printf("%d%c", code[l], l==m?'\n':' ');// printf("%lld %lld\n", hm[cur].state[k], hm[cur].cnt[k]);// } } LL ans=Inf;// printf("size=%d\n",hm[cur].size); for(int i=0;i<hm[cur].size;i++) ans=min(ans, hm[cur].cnt[i]); printf("%lld\n", ans<Inf?ans-2:0);}int main(){ while(~scanf("%d%d",&n ,&m)){ if(n==0&&m==0) break; init(); solve(); } return 0;}
ZOJ 3466
n*8的图形,并且由正六边形构成,给出不可达点,求经过所有可达点一次的回路的条数。
其实这个图形转个90度看解决起来更方便,每个位置可能引出插头的方向有3个,右,左下,右下,shift操作的时候注意行与行并不是对齐的,偶数行转奇数行才要shift两格,而奇数行转偶数行不需要shift。
#include<stdio.h>#include<string.h>#include<stdlib.h>#include<iostream>#define LL long longusing namespace std;const int max_size=1e6+50;const int hash_mod=1e5+7;const int maxc=15;struct HASHMAP{ int size; int head[hash_mod], next[max_size]; LL state[max_size], cnt[max_size]; void init(){ size=0; memset(head, -1, sizeof head); } void push(LL st,LL c){ int i, h=st%hash_mod; for(i=head[h];i!=-1;i=next[i]) if(state[i]==st){ cnt[i]+=c; return; } state[size]=st; cnt[size]=c; next[size]=head[h]; head[h]=size++; }};HASHMAP hm[2];int code[2*maxc], id[maxc];int n, m;int G[maxc][maxc];void decode(int code[],int m,LL st){ for(int i=m;i>=0;i--){ code[i]=st&1; st>>=1; }}LL encode(int code[],int m){ LL ret=0; for(int i=0;i<=m;i++){ //if(id[code[i]]==-1) id[code[i]]=++cnt; //code[i]=id[code[i]]; ret<<=1; ret|=code[i]; } return ret;}void shift(int code[],int m){//even->odd && c==m for(int i=m;i>1;i--) code[i]=code[i-2]; code[0]=code[1]=0;}void dpblank(int r,int c,int cur){ int left, up, up2; int t1, t2; if(r%2) t1=c, t2=c+1; else t1=c-1, t2=c; for(int i=0;i<hm[cur].size;i++){ LL st=hm[cur].state[i]; LL cnt=hm[cur].cnt[i]; decode(code, 2*m, st); left=code[2*c-2]; up=code[2*c-1]; up2=code[2*c]; if(left&&up&&up2){ continue; }else if((left&&up)||(left&&up2)||(up&&up2)){ code[2*c]=code[2*c-1]=code[2*c-2]=0; if(c==m&&r%2) shift(code, 2*m); hm[cur^1].push(encode(code, 2*m), cnt); }else if(left||up||up2){ if(G[r][c+1]){ code[2*c]=1; code[2*c-2]=code[2*c-1]=0; hm[cur^1].push(encode(code, 2*m), cnt); } if(G[r+1][t1]){ code[2*c-2]=1; code[2*c]=code[2*c-1]=0; if(c==m&&r%2) shift(code, 2*m); hm[cur^1].push(encode(code, 2*m), cnt); } if(G[r+1][t2]){ code[2*c-1]=1; code[2*c]=code[2*c-2]=0; if(c==m&&r%2) shift(code, 2*m); hm[cur^1].push(encode(code, 2*m), cnt); } }else{ if(G[r][c+1]&&G[r+1][t1]){ code[2*c]=code[2*c-2]=1; code[2*c-1]=0; hm[cur^1].push(encode(code, 2*m), cnt); } if(G[r][c+1]&&G[r+1][t2]){ code[2*c]=code[2*c-1]=1; code[2*c-2]=0; hm[cur^1].push(encode(code, 2*m), cnt); } if(G[r+1][t1]&&G[r+1][t2]){ code[2*c]=0; code[2*c-1]=code[2*c-2]=1; if(c==m&&r%2) shift(code, 2*m); hm[cur^1].push(encode(code, 2*m), cnt); } } }}void dpblock(int r,int c,int cur){ for(int i=0;i<hm[cur].size;i++){ LL st=hm[cur].state[i]; LL cnt=hm[cur].cnt[i]; decode(code, 2*m, st); code[2*c-2]=code[2*c-1]=code[2*c]=0; if(r%2&&c==m) shift(code, 2*m); hm[cur^1].push(encode(code, 2*m), cnt); }}void init(){ char s[5]; memset(G, 0, sizeof G); for(int i=1;i<=8;i++) for(int j=1;j<=n;j++) G[i][j]=1; for(int i=0;i<m;i++){ scanf("%s", s); int r=s[0]-'A'+1; int c=s[1]-'A'+1; G[c][r]=0; } m=n; n=8;}void solve(){ int cur=0; hm[cur].init(); hm[cur].push(0, 1); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ hm[cur^1].init(); if(G[i][j]) dpblank(i, j, cur); else dpblock(i, j, cur); cur^=1;// for(int k=0;k<hm[cur].size;k++)// printf("r=%d c=%d state=%lld cnt=%lld\n", i, j, hm[cur].state[k], hm[cur].cnt[k]); } LL ans=0; for(int i=0;i<hm[cur].size;i++) if(hm[cur].state[i]==0) ans+=hm[cur].cnt[i]; printf("%lld\n", ans);}int main(){ while(~scanf("%d%d",&n, &m)){ init(); solve(); } return 0;}
ZOJ 3213
给出矩阵,不限起点,不限终点,找出一条权值和最大的路径,路径上每个点只能经过一次。额外加一个标记位,来记录端点的个数,当端点个数不足2时,可以考虑把当前点作为端点。
#include<stdio.h>#include<string.h>#include<stdlib.h>#include<iostream>#include<algorithm>#define LL long longusing namespace std;const int hash_mod=3e4+7;const int state_size=1e6+50;const int maxc=15;int id[maxc], code[maxc], G[maxc][maxc];struct HASHMAP{ int head[hash_mod], next[state_size], st_size; int state[state_size]; int cnt[state_size]; void init(){ st_size=0; memset(head, -1, sizeof head); } void push(int st,int c){ int i, h=st%hash_mod; for(i=head[h];i!=-1;i=next[i]) if(st==state[i]){ cnt[i]=max(cnt[i], c); return; } cnt[st_size]=c; state[st_size]=st; next[st_size]=head[h]; head[h]=st_size++; }};HASHMAP hm[2];int n, m, nums;int encode(int code[], int m){ int ret=0; int cnt=0; memset(id, -1, sizeof id); id[0]=0; for(int i=0;i<=m;i++){ if(id[code[i]]==-1) id[code[i]]=++cnt; code[i]=id[code[i]]; ret<<=3; ret|=code[i]; } ret<<=3; ret|=nums; return ret;}void decode(int code[], int m, int st){ nums=st&7; st>>=3; for(int i=m;i>=0;i--){ code[i]=st&7; st>>=3; }}void shift(int code[], int m){ for(int i=m;i>0;i--) code[i]=code[i-1]; code[0]=0;}void dpblank(int r,int c,int cur){ int left, up; for(int i=0;i<hm[cur].st_size;i++){ int cnt=hm[cur].cnt[i]; int st=hm[cur].state[i]; decode(code, m, st); left=code[c-1]; up=code[c]; if(left&&up){// 11 if(left!=up){//not in the same cc code[c-1]=code[c]=0; for(int j=0;j<=m;j++)//combine the two cc and update code if(code[j]==left) code[j]=up; hm[cur^1].push(encode(code, c==m?m-1:m), cnt+G[r][c]); } }else if(left||up){ int tmp; if(left) tmp=left; else tmp=up; if(G[r+1][c]){ code[c-1]=tmp; code[c]=0; hm[cur^1].push(encode(code, c==m?m-1:m), cnt+G[r][c]); } if(G[r][c+1]){ code[c-1]=0; code[c]=tmp; hm[cur^1].push(encode(code, m), cnt+G[r][c]); } if(nums<2){ nums++; code[c-1]=code[c]=0; hm[cur^1].push(encode(code, c==m?m-1:m), cnt+G[r][c]); } }else{ code[c-1]=code[c]=0; hm[cur^1].push(encode(code, c==m?m-1:m), cnt); if(G[r+1][c]&&G[r][c+1]){ code[c-1]=code[c]=13;//assign a huge value hm[cur^1].push(encode(code, m), cnt+G[r][c]); } if(nums<2){ nums++; if(G[r+1][c]){ code[c-1]=13; code[c]=0; hm[cur^1].push(encode(code, c==m?m-1:m), cnt+G[r][c]); } if(G[r][c+1]){ code[c-1]=0; code[c]=13; hm[cur^1].push(encode(code, m), cnt+G[r][c]); } } } }}void dpblock(int r,int c,int cur){ for(int i=0;i<hm[cur].st_size;i++){ decode(code, m, hm[cur].state[i]); code[c-1]=code[c]=0; hm[cur^1].push(encode(code, c==m?m-1:m), hm[cur].cnt[i]); }}void init(){ char s[maxc]; scanf("%d%d",&n, &m); memset(G, 0, sizeof G); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d", &G[i][j]);}void solve(){ int cur=0; int ans=0; hm[cur].init(); hm[cur].push(0, 0); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ ans=max(ans, G[i][j]); hm[cur^1].init(); if(G[i][j]){ dpblank(i, j, cur); }else{ dpblock(i, j, cur); } cur^=1; } for(int i=0;i<hm[cur].st_size;i++){ ans=max(ans, hm[cur].cnt[i]); } printf("%d\n", ans);}int main(){ int T; scanf("%d",&T); while(T--){ init(); solve(); } return 0;}/*1004 41 2 3 45 0 0 00 100 2 0104 0 2 2*/
HDU 4285
给出矩阵,可达点,不可达点,求只用K条回路恰经过所有点一次的方案数。额外加一个标志位,记录当前回路数,相同联通块合并时回路数加1。
#include<stdio.h>#include<string.h>#include<stdlib.h>#include<iostream>#define LL long longusing namespace std;const int max_size=1e6+50;const int hash_mod=1e5+7;const int maxc=15;const int mod=1e9+7;struct HASHMAP{ int size; LL state[max_size]; int cnt[max_size]; int head[hash_mod], next[max_size]; void init(){ size=0; memset(head, -1, sizeof head); } void push(LL st, int c){ int i, h=st%hash_mod; for(i=head[h];i!=-1;i=next[i]) if(state[i]==st){ cnt[i]=(cnt[i]+c)%mod; return; } state[size]=st; cnt[size]=c%mod; next[size]=head[h]; head[h]=size++; }};HASHMAP hm[2];int id[maxc], code[maxc];int n, m, K, nums;int G[maxc][maxc];LL encode(int code[],int m){ LL ret=0; int cnt=0; memset(id, -1, sizeof id); id[0]=0; for(int i=0;i<=m;i++){ if(id[code[i]]==-1) id[code[i]]=++cnt; code[i]=id[code[i]]; ret<<=3; ret|=code[i]; } ret<<=5; ret|=nums; return ret;}void decode(int code[],int m,LL st){ nums=st&31; st>>=5; for(int i=m;i>=0;i--){ code[i]=st&7; st>>=3; }}void shift(int code[],int m){ for(int i=m;i>0;i--){ code[i]=code[i-1]; } code[0]=0;}void dpblank(int r,int c,int cur){ int left, up; for(int i=0;i<hm[cur].size;i++){ LL st=hm[cur].state[i]; int cnt=hm[cur].cnt[i]; decode(code, m, st); left=code[c-1]; up=code[c]; if(left&&up){ if(left==up){ if(nums>=K) continue; int plugs=0; for(int j=0;j<c-1;j++) if(code[j]) plugs++; if(plugs&1) continue; code[c-1]=code[c]=0; nums++; if(c==m) shift(code, m); hm[cur^1].push(encode(code, m), cnt); }else{ code[c-1]=code[c]=0; for(int j=0;j<=m;j++) if(code[j]==left) code[j]=up; if(c==m) shift(code, m); hm[cur^1].push(encode(code, m), cnt); } }else if(left||up){ int tmp=max(left, up); if(G[r][c+1]){ code[c]=tmp; code[c-1]=0; hm[cur^1].push(encode(code, m), cnt); } if(G[r+1][c]){ code[c]=0; code[c-1]=tmp; if(c==m) shift(code, m); hm[cur^1].push(encode(code, m), cnt); } }else{ if(G[r][c+1]&&G[r+1][c]){ code[c-1]=code[c]=13; hm[cur^1].push(encode(code, m), cnt); } } }}void dpblock(int r,int c,int cur){ for(int i=0;i<hm[cur].size;i++){ LL st=hm[cur].state[i]; int cnt=hm[cur].cnt[i]; decode(code, m, st); code[c-1]=code[c]=0; if(c==m) shift(code, m); hm[cur^1].push(encode(code, m), cnt); }}void init(){ char s[maxc]; scanf("%d%d%d", &n, &m, &K); memset(G, 0, sizeof G); for(int i=1;i<=n;i++){ scanf("%s", s+1); for(int j=1;j<=m;j++) if(s[j]=='.') G[i][j]=1; }}void solve(){ int cur=0; hm[cur].init(); hm[cur].push(0, 1); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ hm[cur^1].init(); if(G[i][j]) dpblank(i, j, cur); else dpblock(i, j, cur); cur^=1; } int ans=0; for(int i=0;i<hm[cur].size;i++){ decode(code, m, hm[cur].state[i]); if(nums==K) ans=(ans+hm[cur].cnt[i])%mod; } printf("%d\n", ans);}int main(){ int T; scanf("%d", &T); while(T--){ init(); solve(); } return 0;}
- 插头DP
- 插头dp
- 插头dp
- 插头dp
- 插头DP
- 插头dp
- hdu 1693 插头dp
- 插头DP【入门】
- hdu 4064 (插头DP)
- poj 3133 插头Dp
- HDU-1693-插头dp
- POJ-1739-插头dp
- 插头DP(HDOJ1693)初识
- 【Learning】适妞来学 插头 dp
- tongji 30029 插头dp
- Hdu 1693 插头dp
- ZOJ 3466 插头dp
- 插头dp--hdu1639
- python快速入门(6)函数
- gethostbyname和hasattr, getattr, setattr函数的使用
- 验证++i和i++的区别
- java 的四大引用
- 以pdo的格式向数据库插入变量
- 插头dp
- Java final关键字详解
- 有趣的算法问题11——X的平方根(二分查找法)
- python快速入门(7)文件
- USB 设备驱动开发之几个重要结构体分析
- Codeforces Round #422 (Div. 2)
- POJ 2609 Ferry Loading 笔记
- python的装饰器和find函数的使用
- 归并排序介绍与分析