插头DP

HDU1693 Eat the Trees

不用分左右插头的DP。关键就是逐格递推。行与行之间的转移看轮廓线发现很happy。

 1 int a[13][13];
 2 ll dp[13][13][1<<15];
 3 int main()
 4 {
 5     freopen("input.txt","r",stdin);
 6     freopen("output.txt","w",stdout);
 7     int T=read(),cs=0;
 8     while(T--)
 9     {
10         int n=read(),m=read();
11         for1(i,n)for1(j,m)a[i][j]=read();
12         dp[0][m][0]=1;
13         for1(i,n)
14          {
15              for0(j,(1<<m)-1)dp[i][0][j<<1]=dp[i-1][m][j];
16              for1(j,m)
17               for0(k,(1<<(m+1))-1)
18                {
19                    int x=1<<(j-1),y=1<<j;
20                    if(a[i][j])
21                    {
22                        dp[i][j][k]=dp[i][j-1][k^x^y];
23                        if(((k&x)!=0)^((k&y)!=0))dp[i][j][k]+=dp[i][j-1][k];
24                    }else dp[i][j][k]=(!(k&x)&&!(k&y))*dp[i][j-1][k];
25                }
26          }
27         printf("Case %d: There are %lld ways to eat the trees.\n",++cs,dp[n][m][0]);
28     }
29     return 0;
30 }
View Code

 URAL1519 Formula 1

真正的插头DP来了。发现很好理解, 写起来略蛋疼。hash表的写法各有各的。注意位运算的优先级。

 1 int n,m,head[2][maxn],tot[2],b[20],now,pre;
 2 bool a[20][20];
 3 ll dp[2][maxn];
 4 struct edge{int go,id,next;}e[2][maxn];
 5 inline void add(int v,ll w)
 6 {
 7     int z=v%mod;
 8     for5(now,i,z)if(y==v){dp[now][i]+=w;return;}
 9     e[now][++tot[now]]=(edge){v,z,head[now][z]};head[now][z]=tot[now];
10     dp[now][tot[now]]=w;
11 }
12 int main()
13 {
14     freopen("input.txt","r",stdin);
15     freopen("output.txt","w",stdout);
16     for0(i,20)b[i]=i<<1;
17     now=0;pre=1;
18     n=read();m=read();int xx,yy;ll ans=0;
19     for1(i,n)for1(j,m)
20     {
21         char ch=getchar();while(ch!='*'&&ch!='.')ch=getchar();a[i][j]=ch=='.';
22         if(a[i][j])xx=i,yy=j;
23     }
24     add(0,1);
25     for1(i,n)
26     {
27      for1(j,tot[now])e[now][j].go<<=2;
28      for1(j,m)
29       {
30         swap(now,pre);
31         for1(k,tot[now])head[now][e[now][k].id]=0;tot[now]=0;
32         for1(k,tot[pre])
33         {
34             int v=e[pre][k].go,x=v>>b[j-1]&3,y=v>>b[j]&3;ll w=dp[pre][k];
35             if(!a[i][j]){if(x+y==0)add(v,w);}
36             else if(x+y==0)
37             {
38                 if(!a[i][j+1]||!a[i+1][j])continue;
39                 add(v^(1<<b[j-1])^(2<<b[j]),w);
40             }
41             else if(!x&&y)
42             {
43                 if(a[i][j+1])add(v,w);
44                 if(a[i+1][j])add(v^(y<<b[j-1])^(y<<b[j]),w);
45             }else if(x&&!y)
46             {
47                 if(a[i+1][j])add(v,w);
48                 if(a[i][j+1])add(v^(x<<b[j-1])^(x<<b[j]),w);
49             }else if(x+y==2)
50             {
51                 int t1=1,t2;
52                 for2(l,j+1,m)
53                 {
54                     t2=v>>b[l]&3;
55                     if(t2==1)t1++;
56                     if(t2==2)t1--;
57                     if(!t1){add((v^(x<<b[j-1])^(y<<b[j]))-(1<<b[l]),w);break;}
58                 }
59             }else if(x+y==4)
60             {
61                 int t1=1,t2;
62                 for3(l,j-2,0)
63                 {
64                     t2=v>>b[l]&3;
65                     if(t2==2)t1++;
66                     if(t2==1)t1--;
67                     if(!t1){add((v^(x<<b[j-1])^(y<<b[j]))+(1<<b[l]),w);break;}
68                 }
69             }else if(x==2&&y==1)add(v^(x<<b[j-1])^(y<<b[j]),w);
70              else if(i==xx&&j==yy)ans+=w;
71         }
72       }
73     }
74     cout<<ans<<endl;
75     return 0;
76 }
View Code

 HDU1964 Pipes

套上面的代码,把取和改成取min。什么?你说读入?读入优化大法好。直接过滤无用字符。

 1 int n,m,head[2][maxn],tot[2],b[20],now,pre,dp[2][maxn],a[20][20],c[20][20];
 2 struct edge{int go,id,next;}e[2][maxn];
 3 inline void add(int v,int w)
 4 {
 5     int z=v%mod;
 6     for5(now,i,z)if(y==v){dp[now][i]=min(dp[now][i],w);return;}
 7     e[now][++tot[now]]=(edge){v,z,head[now][z]};head[now][z]=tot[now];
 8     dp[now][tot[now]]=w;
 9 }
10 inline bool check(int x,int y){return x>=1&&x<=n&&y>=1&&y<=m;}
11 int main()
12 {
13     freopen("input.txt","r",stdin);
14     freopen("output.txt","w",stdout);
15     for0(i,20)b[i]=i<<1;
16     int T=read();
17     while(T--)
18     {
19     now=0;pre=1;
20     n=read();m=read();int ans=inf;
21     memset(a,0,sizeof(a));memset(c,0,sizeof(c));
22     for2(i,2,2*n)for1(j,i&1?m:m-1)i&1?c[i>>1][j]=read():a[i>>1][j]=read();
23     add(0,0);
24     for1(i,n)
25     {
26      for1(j,tot[now])e[now][j].go<<=2;
27      for1(j,m)
28       {
29         swap(now,pre);
30         for1(k,tot[now])head[now][e[now][k].id]=0;tot[now]=0;
31         for1(k,tot[pre])
32         {
33             int v=e[pre][k].go,x=v>>b[j-1]&3,y=v>>b[j]&3,w=dp[pre][k];
34             if(x+y==0)
35             {
36                 if(!check(i,j+1)||!check(i+1,j))continue;
37                 add(v^(1<<b[j-1])^(2<<b[j]),w+c[i][j]+a[i][j]);
38             }
39             else if(!x&&y)
40             {
41                 if(check(i,j+1))add(v,w+a[i][j]);
42                 if(check(i+1,j))add(v^(y<<b[j-1])^(y<<b[j]),w+c[i][j]);
43             }else if(x&&!y)
44             {
45                 if(check(i+1,j))add(v,w+c[i][j]);
46                 if(check(i,j+1))add(v^(x<<b[j-1])^(x<<b[j]),w+a[i][j]);
47             }else if(x+y==2)
48             {
49                 int t1=1,t2;
50                 for2(l,j+1,m)
51                 {
52                     t2=v>>b[l]&3;
53                     if(t2==1)t1++;
54                     if(t2==2)t1--;
55                     if(!t1){add((v^(x<<b[j-1])^(y<<b[j]))-(1<<b[l]),w);break;}
56                 }
57             }else if(x+y==4)
58             {
59                 int t1=1,t2;
60                 for3(l,j-2,0)
61                 {
62                     t2=v>>b[l]&3;
63                     if(t2==2)t1++;
64                     if(t2==1)t1--;
65                     if(!t1){add((v^(x<<b[j-1])^(y<<b[j]))+(1<<b[l]),w);break;}
66                 }
67             }else if(x==2&&y==1)add(v^(x<<b[j-1])^(y<<b[j]),w);
68              else if(i==n&&j==m)ans=min(ans,w);
69         }
70       }
71     }
72     cout<<ans<<endl;
73     }
74     return 0;
75 }
View Code

 POJ1739 Tony's Tour

套上上面的代码,强行把欧拉路改成欧拉回路,在棋盘下面加两行即可。

 1 int n,m,head[2][maxn],tot[2],b[20],now,pre;
 2 bool a[20][20];
 3 ll dp[2][maxn];
 4 struct edge{int go,id,next;}e[2][maxn];
 5 inline void add(int v,ll w)
 6 {
 7     int z=v%mod;
 8     for5(now,i,z)if(y==v){dp[now][i]+=w;return;}
 9     e[now][++tot[now]]=(edge){v,z,head[now][z]};head[now][z]=tot[now];
10     dp[now][tot[now]]=w;
11 }
12 int main()
13 {
14     freopen("input.txt","r",stdin);
15     freopen("output.txt","w",stdout);
16     for0(i,20)b[i]=i<<1;
17     now=0;pre=1;
18     while(1)
19     {
20     n=read();m=read();ll ans=0;
21     memset(a,0,sizeof(a));
22     if(!n&&!m)break;
23     for1(i,n)for1(j,m)
24     {
25         char ch=getchar();while(ch!='#'&&ch!='.')ch=getchar();a[i][j]=ch=='.';
26     }
27     for1(i,m)if(i==1||i==m)a[n+1][i]=1;else a[n+1][i]=0;
28     for1(i,m)a[n+2][i]=1;
29     n+=2;
30     add(0,1);
31     for1(i,n)
32     {
33      for1(j,tot[now])e[now][j].go<<=2;
34      for1(j,m)
35       {
36         swap(now,pre);
37         for1(k,tot[now])head[now][e[now][k].id]=0;tot[now]=0;
38         for1(k,tot[pre])
39         {
40             int v=e[pre][k].go,x=v>>b[j-1]&3,y=v>>b[j]&3;ll w=dp[pre][k];
41             if(!a[i][j]){if(x+y==0)add(v,w);}
42             else if(x+y==0)
43             {
44                 if(!a[i][j+1]||!a[i+1][j])continue;
45                 add(v^(1<<b[j-1])^(2<<b[j]),w);
46             }
47             else if(!x&&y)
48             {
49                 if(a[i][j+1])add(v,w);
50                 if(a[i+1][j])add(v^(y<<b[j-1])^(y<<b[j]),w);
51             }else if(x&&!y)
52             {
53                 if(a[i+1][j])add(v,w);
54                 if(a[i][j+1])add(v^(x<<b[j-1])^(x<<b[j]),w);
55             }else if(x+y==2)
56             {
57                 int t1=1,t2;
58                 for2(l,j+1,m)
59                 {
60                     t2=v>>b[l]&3;
61                     if(t2==1)t1++;
62                     if(t2==2)t1--;
63                     if(!t1){add((v^(x<<b[j-1])^(y<<b[j]))-(1<<b[l]),w);break;}
64                 }
65             }else if(x+y==4)
66             {
67                 int t1=1,t2;
68                 for3(l,j-2,0)
69                 {
70                     t2=v>>b[l]&3;
71                     if(t2==2)t1++;
72                     if(t2==1)t1--;
73                     if(!t1){add((v^(x<<b[j-1])^(y<<b[j]))+(1<<b[l]),w);break;}
74                 }
75             }else if(x==2&&y==1)add(v^(x<<b[j-1])^(y<<b[j]),w);
76              else if(i==n&&j==m)ans+=w;
77         }
78       }
79     }
80     cout<<ans<<endl;
81     }
82     return 0;
83 }
View Code

 HDU3377 Plan

套上上面的代码。。。卧槽这都什么题啊。。。求路径补成回路,在外面加一圈权值非常大的。

 1 int n,m,head[2][maxn],tot[2],b[20],now,pre;
 2 ll a[20][20],dp[2][maxn];
 3 struct edge{int go,id,next;}e[2][maxn];
 4 inline void add(int v,ll w)
 5 {
 6     int z=v%mod;
 7     for5(now,i,z)if(y==v){dp[now][i]=max(dp[now][i],w);return;}
 8     e[now][++tot[now]]=(edge){v,z,head[now][z]};head[now][z]=tot[now];
 9     dp[now][tot[now]]=w;
10 }
11 inline bool check(int x,int y){return x>=1&&x<=n&&y>=1&&y<=m;}
12 int main()
13 {
14     freopen("input.txt","r",stdin);
15     freopen("output.txt","w",stdout);
16     for0(i,20)b[i]=i<<1;int cs=0;
17     while(scanf("%d%d",&n,&m)!=EOF)
18     {
19     now=0;pre=1;
20     ll ans=-inf;
21     memset(a,0,sizeof(a));
22     n+=2;m+=2;
23     for1(i,m)a[1][i]=inf;
24     for1(i,n)a[i][m]=inf;
25     a[2][1]=a[n][m-1]=inf;
26     for2(i,2,m-1)a[2][i]=-inf;
27     for2(i,2,n-1)a[i][m-1]=-inf;
28     for2(i,3,n)for1(j,m-2)a[i][j]=read();
29     //for1(i,n)for1(j,m)printf("%I64d%c",a[i][j],j==m?'\n':' ');
30     memset(head,0,sizeof(head));tot[0]=tot[1]=0;
31     add(0,0);
32     for1(i,n)
33     {
34      for1(j,tot[now])e[now][j].go<<=2;
35      for1(j,m)
36       {
37         swap(now,pre);
38         for1(k,tot[now])head[now][e[now][k].id]=0;tot[now]=0;
39         for1(k,tot[pre])
40         {
41             int v=e[pre][k].go,x=v>>b[j-1]&3,y=v>>b[j]&3;ll w=dp[pre][k];
42             if(x+y==0)
43             {
44                 add(v,w);
45                 if(!check(i,j+1)||!check(i+1,j))continue;
46                 add(v^(1<<b[j-1])^(2<<b[j]),w+a[i][j]);
47             }
48             else if(!x&&y)
49             {
50                 if(check(i,j+1))add(v,w+a[i][j]);
51                 if(check(i+1,j))add(v^(y<<b[j-1])^(y<<b[j]),w+a[i][j]);
52             }else if(x&&!y)
53             {
54                 if(check(i+1,j))add(v,w+a[i][j]);
55                 if(check(i,j+1))add(v^(x<<b[j-1])^(x<<b[j]),w+a[i][j]);
56             }else if(x+y==2)
57             {
58                 int t1=1,t2;
59                 for2(l,j+1,m)
60                 {
61                     t2=v>>b[l]&3;
62                     if(t2==1)t1++;
63                     if(t2==2)t1--;
64                     if(!t1){add((v^(x<<b[j-1])^(y<<b[j]))-(1<<b[l]),w+a[i][j]);break;}
65                 }
66             }else if(x+y==4)
67             {
68                 int t1=1,t2;
69                 for3(l,j-2,0)
70                 {
71                     t2=v>>b[l]&3;
72                     if(t2==2)t1++;
73                     if(t2==1)t1--;
74                     if(!t1){add((v^(x<<b[j-1])^(y<<b[j]))+(1<<b[l]),w+a[i][j]);break;}
75                 }
76             }else if(x==2&&y==1)add(v^(x<<b[j-1])^(y<<b[j]),w+a[i][j]);
77              else if(i==n&&j==m)ans=max(ans,w+a[i][j]);
78         }
79       }
80     }
81     printf("Case %d: ",++cs);cout<<(ans-(ll)(m+n+1)*inf)<<endl;
82     }
83     return 0;
84 }
View Code

 SCOI2011地板

这才叫插头DP题嘛!用0表示此处无插头,1表示有但是还需要转弯,2表示有并且不需要转弯。

转移:

00->01|10|22

10->20|01

01->10|02

20->00|02

02->00|20

11->00

 1 int n,m,head[2][maxn],tot[2],b[20],now,pre;
 2 bool a[101][101];
 3 ll dp[2][maxn];
 4 struct edge{int go,id,next;}e[2][maxn];
 5 inline void add(int v,ll w)
 6 {
 7     //cout<<v<<' '<<w<<endl;
 8     int z=v%p;
 9     for5(now,i,z)if(y==v){(dp[now][i]+=w)%=mod;return;}
10     e[now][++tot[now]]=(edge){v,z,head[now][z]};head[now][z]=tot[now];
11     dp[now][tot[now]]=w;
12 }
13 int main()
14 {
15     freopen("input.txt","r",stdin);
16     freopen("output.txt","w",stdout);
17     for0(i,20)b[i]=i<<1;
18     n=read();m=read();
19     for1(i,n)for1(j,m)
20     {
21         char ch=getchar();while(ch!='*'&&ch!='_')ch=getchar();
22         if(n>m)a[i][j]=ch=='_';else a[j][i]=ch=='_';
23     }
24     if(n<m)swap(n,m);
25     now=0;pre=1;
26     add(0,1);
27     for1(i,n)
28     {
29         //cout<<tot[now]<<endl;
30         for1(j,tot[now])e[now][j].go<<=2;
31         for1(j,m)
32         {
33             swap(now,pre);
34             for1(k,tot[now])head[now][e[now][k].id]=0;tot[now]=0;
35             for1(k,tot[pre])
36             {
37                 int v=e[pre][k].go,x=v>>b[j-1]&3,y=v>>b[j]&3;ll w=dp[pre][k];
38                 if(!a[i][j]){if(x+y==0)add(v,w);}
39                 else if(x+y==0)
40                 {
41                     if(a[i+1][j])add(v^(1<<b[j-1]),w);
42                     if(a[i][j+1])add(v^(1<<b[j]),w);
43                     if(a[i+1][j]&&a[i][j+1])add(v^(2<<b[j-1])^(2<<b[j]),w);
44                 }else if(x==1&&!y)
45                 {
46                     if(a[i+1][j])add(v+(1<<b[j-1]),w);
47                     if(a[i][j+1])add(v^(1<<b[j-1])^(1<<b[j]),w);
48                 }else if(!x&&y==1)
49                 {
50                     if(a[i][j+1])add(v+(1<<b[j]),w);
51                     if(a[i+1][j])add(v^(1<<b[j-1])^(1<<b[j]),w);
52                 }else if(x==2&&!y)
53                 {
54                     add(v^(2<<b[j-1]),w);
55                     if(a[i][j+1])add(v^(2<<b[j-1])^(2<<b[j]),w);
56                 }else if(!x&&y==2)
57                 {
58                     add(v^(2<<b[j]),w);
59                     if(a[i+1][j])add(v^(2<<b[j-1])^(2<<b[j]),w);
60                 }else if(x==1&&y==1)
61                 {
62                     add(v^(1<<b[j-1])^(1<<b[j]),w);
63                 }
64             }
65         }
66     }
67     cout<<(tot[now]?dp[now][1]:0)<<endl;
68     return 0;
69 }
View Code

 

HNOI2004邮递员

插头DP求回路。加个高精度。AC了之后发现时光机说这题有点问题。Orz

  1 int n,m,head[2][maxm],tot[2],b[20],now,pre;
  2 bool a[20][20];
  3 struct edge{int go,id,next;}e[2][maxn];
  4 struct bignum
  5 {
  6     int x[10],n;
  7     void init(int b)
  8     {
  9         memset(x,0,sizeof(x)); 
 10         x[n=1]=b;
 11     }
 12     void rebuild()
 13     {
 14         for(int i=1;i<=n||x[i];i++)
 15         {
 16             x[i+1]+=x[i]/bs;
 17             x[i]%=bs;
 18             if(i>n)n=i;
 19         }
 20     }    
 21     void operator +=(bignum b)
 22     {
 23         n=max(n,b.n);
 24         for1(i,n)x[i]+=b.x[i];
 25         this->rebuild();
 26     }
 27     void print()
 28     {
 29         printf("%d",x[n]);
 30         for3(i,n-1,1)printf("%04d",x[i]);
 31         printf("\n");
 32     }
 33     void operator *=(int b)
 34     {
 35         for1(i,n)x[i]*=b;
 36         this->rebuild();
 37     }
 38 }dp[2][maxn];
 39 inline void add(int v,bignum w)
 40 {
 41     int z=v%mod;
 42     for5(now,i,z)if(y==v){dp[now][i]+=w;return;}
 43     e[now][++tot[now]]=(edge){v,z,head[now][z]};head[now][z]=tot[now];
 44     dp[now][tot[now]]=w;
 45 }
 46 int main()
 47 {
 48     freopen("input.txt","r",stdin);
 49     freopen("output.txt","w",stdout);
 50     for0(i,20)b[i]=i<<1;
 51     now=0;pre=1;
 52     n=read();m=read();if(n<m)swap(n,m);
 53     if(m==1){printf("%d\n",1);return 0;}
 54     for1(i,n)for1(j,m)a[i][j]=1;
 55     bignum ans;ans.init(1);
 56     add(0,ans);
 57     ans.init(0);
 58     for1(i,n)
 59     {
 60      for1(j,tot[now])e[now][j].go<<=2;
 61      for1(j,m)
 62       {
 63         swap(now,pre);
 64         for1(k,tot[now])head[now][e[now][k].id]=0;tot[now]=0;
 65         for1(k,tot[pre])
 66         {
 67             int v=e[pre][k].go,x=v>>b[j-1]&3,y=v>>b[j]&3;bignum w=dp[pre][k];
 68             if(!a[i][j]){if(x+y==0)add(v,w);}
 69             else if(x+y==0)
 70             {
 71                 if(!a[i][j+1]||!a[i+1][j])continue;
 72                 add(v^(1<<b[j-1])^(2<<b[j]),w);
 73             }
 74             else if(!x&&y)
 75             {
 76                 if(a[i][j+1])add(v,w);
 77                 if(a[i+1][j])add(v^(y<<b[j-1])^(y<<b[j]),w);
 78             }else if(x&&!y)
 79             {
 80                 if(a[i+1][j])add(v,w);
 81                 if(a[i][j+1])add(v^(x<<b[j-1])^(x<<b[j]),w);
 82             }else if(x+y==2)
 83             {
 84                 int t1=1,t2;
 85                 for2(l,j+1,m)
 86                 {
 87                     t2=v>>b[l]&3;
 88                     if(t2==1)t1++;
 89                     if(t2==2)t1--;
 90                     if(!t1){add((v^(x<<b[j-1])^(y<<b[j]))-(1<<b[l]),w);break;}
 91                 }
 92             }else if(x+y==4)
 93             {
 94                 int t1=1,t2;
 95                 for3(l,j-2,0)
 96                 {
 97                     t2=v>>b[l]&3;
 98                     if(t2==2)t1++;
 99                     if(t2==1)t1--;
100                     if(!t1){add((v^(x<<b[j-1])^(y<<b[j]))+(1<<b[l]),w);break;}
101                 }
102             }else if(x==2&&y==1)add(v^(x<<b[j-1])^(y<<b[j]),w);
103              else if(i==n&&j==m)ans+=w; 
104              //if(x==1&&y==2)add(v^(x<<b[j-1])^(y<<b[j]),w);
105         }
106       }
107     }
108     ans*=2;
109     ans.print();
110     return 0;
111 }
View Code

 

posted @ 2015-04-04 11:00 ZYF-ZYF Views(...) Comments(...) Edit 收藏