插頭dp


長沙大佬的博客

Orz高一進隊,Orz pku一本,跟我這種人真是雲泥之別

今年二月我還不知道在哪個地方玩泥巴的時候人家都已經把插頭dp打得爐火純青了,Orz orz 

 

大佬的博客寫得非常好了,我就隨便口胡兩句

一開始不是很懂這玩意,直到看到另一個大佬說的一句話

 

  “值得注意的一點是,插頭不是表示將要去某處的虛擬狀態,而是表示已經到達某處的現實狀態。

 

  也就是說,如果有一個插頭指向某個格子,那么這個格子已經和插頭來源聯通了,我們接下來要考慮的是從這個插頭往哪里走。”

 

任意條回路的情況,用輪廓線dp這個路徑,輪廓線上就是若干向右或向支出來的部分,這種東西就被取名叫插頭,用二進制狀態表示每單位輪廓線上有沒有這種支出來的插頭-也就是一條路徑經過它並且沒成回路下一步要繼續沿着支出的方向走。

如圖,紅色的是一條輪廓線,綠色代表插頭,插頭並不表示路徑的方向,僅表示路徑接下來應向那邊延伸(淺綠色虛線代表這個期望的延伸)

那么對於一個插頭的轉移看能往那邊走就往那邊轉,如圖,紫色代表轉移后的輪廓線,粉色代表左右綠色插頭的兩種轉移方式

對於兩個相鄰的插頭就直接連起來即可(如下圖)。最后的答案就是在最后一個能走的格子中兩個插頭這樣連起來的方案數(當然這時候這條輪廓線前面的那些綠色插頭都是不存在的)。

 

任意條回路的方案數就很容易的求完了。

 

如果只有一條回路,就不能隨便把兩個插頭連起來了(上一段加黑的部分)。因為兩個插頭代表的路徑可能已經聯通了,再相連的話就會提前形成一個回路(如下圖,上方灰色的條路徑使兩個插頭已經聯通,再把淺綠的相連就形成回路了)。

但如果是這樣的路徑連起來就是合法的,因為這兩個插頭一開始在灰色路徑中並沒有聯通

兩種常用的處理辦法:

1、最小表示法,我還沒寫過,不過NOI2007那道題構造轉移的時候也是用最小表示法表示聯通關系的,大概差不多吧

2、括號序列

這樣的聯通關系顯然是構成括號序列的,那么只需要把二進制變成三進制,每個插頭區分是左括號還是右括號就好了

轉移的時候,b1,b2代表綠箭頭指的兩條輪廓線上的插頭情況

只有一個插頭的情況連通性不改變,很好處理,主要需要注意這種轉移(其余請轉移參考最上面大佬的博客,主要是我懶得寫了。。。)

藍色的是原來的括號序列,當用淺綠色把兩個插頭連起來時,聯通性改變

括號序列就變成了這樣,也就是找到右邊對應的第一個右括號改成左括號即可,如下圖。和這種轉移對稱的找左括號的轉移同理。

 

 

HDU - 1693

Eat the Trees

真-最簡單的插頭dp入門題,因為不需要維護插頭的連通性,每條線上只需要記有無插頭,或許直接叫輪廓線dp比較合適。

 1 //Achen
 2 #include<algorithm>
 3 #include<iostream>
 4 #include<cstring>
 5 #include<cstdlib>
 6 #include<vector>
 7 #include<cstdio>
 8 #include<queue>
 9 #include<cmath>
10 #include<set>
11 #include<map>
12 #define Formylove return 0
13 #define For(i,a,b) for(int i=(a);i<=(b);i++)
14 #define Rep(i,a,b) for(int i=(a);i>=(b);i--)
15 const int N=4107; 16 typedef long long LL; 17 typedef double db; 18 using namespace std; 19 int Cas,n,m,a[15][15],ex,ey; 20 LL ans,f[2][N]; 21 
22 template<typename T>void read(T &x) { 23     char ch=getchar(); x=0; T f=1; 24     while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar(); 25     if(ch=='-') f=-1,ch=getchar(); 26     for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f; 27 } 28 
29 LL solve() { 30     LL rs=0; 31     int up=(1<<(m+1))-1,o=0; 32     For(i,0,up) f[o][i]=0; 33     f[o][0]=1; 34     For(i,1,n) { 35         For(j,1,m) { 36             o^=1; 37             For(s,0,up) f[o][s]=0; 38             For(s,0,up) if(f[o^1][s]) { 39                 int ls=j==1?(s<<1):s,b1=(ls&(1<<(j-1))),b2=(ls&(1<<j)); 40                 if(!b1&&!b2&&!a[i][j]) f[o][ls]+=f[o^1][s]; 41                 else if(!b1&&!b2) { 42                     if(a[i+1][j]&&a[i][j+1]) 43                         f[o][ls|(1<<(j-1))|(1<<j)]+=f[o^1][s]; 44  } 45                 else if(!b1) { 46                     if(a[i+1][j]) 47                         f[o][(ls|(1<<(j-1)))^(1<<j)]+=f[o^1][s]; 48                     if(a[i][j+1]) 49                         f[o][ls]+=f[o^1][s]; 50  } 51                 else if(!b2) { 52                     if(a[i+1][j]) 53                         f[o][ls]+=f[o^1][s]; 54                     if(a[i][j+1]) 55                         f[o][(ls^(1<<(j-1)))|(1<<j)]+=f[o^1][s]; 56  } 57                 else { 58                     if(a[i][j]) { 59                         f[o][ls^(1<<(j-1))^(1<<j)]+=f[o^1][s]; 60                         if(i==ex&&j==ey&&(ls^(1<<(j-1))^(1<<j))==0) { 61                             rs+=f[o^1][s]; 62  } 63  } 64  } 65  } 66  } 67  } 68     return rs; 69 } 70 
71 int main() { 72 #ifdef ANS 73     freopen(".in","r",stdin); 74     freopen(".out","w",stdout); 75 #endif
76  read(Cas); 77     For(cas,1,Cas) { 78  read(n); read(m); 79         For(i,1,n) For(j,1,m){ 80  read(a[i][j]); 81             if(a[i][j]) ex=i,ey=j; 82  } 83         ans=solve(); 84         printf("Case %d: There are %lld ways to eat the trees.\n",cas,ans); 85  } 86  Formylove; 87 }
View Code

 

 URAL - 1519

Formula1

需要維護連通性的真-插頭dp. hasn的時候找到了沒有return而是break和把Rep寫成For調了半個小時。。。 

 1 //Achen
 2 #include<algorithm>
 3 #include<iostream>
 4 #include<cstring>
 5 #include<cstdlib>
 6 #include<vector>
 7 #include<cstdio>
 8 #include<queue>
 9 #include<cmath>
 10 #include<set>
 11 #include<map>
 12 #define Formylove return 0
 13 #define For(i,a,b) for(int i=(a);i<=(b);i++)
 14 #define Rep(i,a,b) for(int i=(a);i>=(b);i--)
 15 const int N=1594327,p=299983;  16 typedef long long LL;  17 typedef double db;  18 using namespace std;  19 int n,m,a[15][15],ex,ey,power[20];  20 char mp[15];  21 
 22 template<typename T>void read(T &x) {  23     char ch=getchar(); x=0; T f=1;  24     while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();  25     if(ch=='-') f=-1,ch=getchar();  26     for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;  27 }  28 
 29 LL f[2][N];  30 int S[2][N];  31 
 32 int o,fir[p+10],nxt[N],tot[2];  33 void ins(int s,LL val) {  34     int tp=s%p+1;  35     for(int i=fir[tp];i;i=nxt[i]) if(S[o][i]==s) {  36         f[o][i]+=val; return;  37  }  38     nxt[++tot[o]]=fir[tp]; fir[tp]=tot[o];  39     S[o][tot[o]]=s; f[o][tot[o]]=val;  40 }  41 
 42 //f 方案數 S hash前的狀態 (4進制) 
 43 LL solve() {  44     LL rs=0;  45     o=1;  46     S[o][++tot[o]]=0;  47     f[o][tot[o]]=1;  48     For(i,1,n) For(j,1,m) {  49         o^=1;  50         tot[o]=0;  51         memset(fir,0,sizeof(fir));  52         For(zt,1,tot[o^1]) {  53             int s=j==1?(S[o^1][zt]<<2):S[o^1][zt];  54             LL num=f[o^1][zt];  55             int b1=(s>>(2*j-2))%4,b2=(s>>(2*j))%4;  56             if(!a[i][j]) {  57                 if(!b1&&!b2) ins(s,num);  58  }  59             else if(!b1&&!b2) {  60                 if(a[i+1][j]&&a[i][j+1]) ins(s+power[j-1]+power[j]*2,num);  61  }  62             else if(!b1) {  63                 if(a[i+1][j]) ins(s+b2*power[j-1]-b2*power[j],num);  64                 if(a[i][j+1]) ins(s,num);  65  }  66             else if(!b2) {  67                 if(a[i][j+1]) ins(s-b1*power[j-1]+b1*power[j],num);  68                 if(a[i+1][j]) ins(s,num);  69  }  70             else if(b1==1&&b2==1) {  71                 int kl=1;  72                 For(t,j+1,m) {  73                     if((s>>(2*t))%4==1) kl++;  74                     if((s>>(2*t))%4==2) kl--;  75                     if(!kl) {  76                         ins(s-power[j-1]-power[j]-power[t],num);  77                         break;  78  }  79  }  80  }  81             else if(b1==2&&b2==2) {  82                 int kl=1;  83                 Rep(t,j-2,0) {  84                     if((s>>(2*t))%4==2) kl++;  85                     if((s>>(2*t))%4==1) kl--;  86                     if(!kl) {  87                         ins(s-2*power[j-1]-2*power[j]+power[t],num);  88                         break;  89  }  90  }  91  }  92             else if(b1==2&&b2==1) ins(s-2*power[j-1]-power[j],num);  93             else if(b1==1&&b2==2&&i==ex&&j==ey)  94                 rs+=num;  95  }  96  }  97     return rs;  98 }  99 
100 int main() { 101 #ifdef ANS 102     freopen(".in","r",stdin); 103     freopen(".out","w",stdout); 104 #endif
105  read(n); read(m); 106     For(i,1,n) { 107         scanf("%s",mp+1); 108         For(j,1,m) if(mp[j]=='.') { 109             a[i][j]=1; 110             ex=i; ey=j; 111  } 112  } 113     power[0]=1; 114     For(i,1,15) power[i]=(power[i-1]<<2); 115     LL ans=solve(); 116     printf("%lld\n",ans); 117  Formylove; 118 }
View Code

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM