标签:shift c++ 能力 插头dp else div int space check
4月真是没写啥题,这题还是月初写的……
不错的插头dp,首先由n和m的范围知肯定是轮廓线是横向划的
问题的难点在于怎么处理下面两个问题
1.怎么处理独立插头
2.怎么处理完全将W和L左右隔开
先说独立插头,一开始我是增加独立插头位来处理的,一直wa……
后来意识到,因为独立插头一定是在第一行和最后一行唯一的,那么假定最顶部有m中状态,每种状态是一个位子上右下插头,最后一行类似处理,这样就解决了
完全将W和L左右隔开比较简单,这要看当前如果是W,则这个格子左边的下插头一定是偶数个,是L则为奇数个,画个图即可理解。
感觉自己插头dp的代码能力还是不足啊
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 typedef long long ll; 5 const int mo=30007; 6 const int maxl=2000010; 7 char s[30]; 8 int n,m,ans,en,p,a[30][30],v[15],b[15],c[15]; 9 10 struct node{ 11 int p[mo],nex[maxl],len,f[maxl]; 12 ll st[maxl]; 13 void clr() 14 { 15 len=0; memset(p,255,sizeof(p)); 16 } 17 void push(ll nw,int s) 18 { 19 int x=nw%mo; 20 for (int i=p[x];i!=-1; i=nex[i]) 21 if (st[i]==nw) 22 { 23 f[i]=min(f[i],s); 24 return; 25 } 26 st[++len]=nw; f[len]=s; 27 nex[len]=p[x]; p[x]=len; 28 } 29 } h[2]; 30 31 void get(ll st) 32 { 33 for (int i=m; i>=0; i--) 34 { 35 c[i]=st&7; 36 st>>=3; 37 } 38 } 39 40 ll put() 41 { 42 memset(v,255,sizeof(v)); v[0]=0; 43 ll st=0; int t=0; 44 for (int i=0; i<=m; i++) 45 { 46 if (v[b[i]]==-1) v[b[i]]=++t; 47 b[i]=v[b[i]]; 48 st<<=3; st|=b[i]; 49 } 50 return st; 51 } 52 53 void shift() 54 { 55 for (int i=m;i; i--) b[i]=b[i-1]; 56 b[0]=0; 57 } 58 59 int check(int j) 60 { 61 int f=0; 62 for (int i=0; i<=j; i++) 63 f+=(c[i]>0); 64 return f; 65 } 66 67 void dp(int i,int j) 68 { 69 for (int k=1; k<=h[p^1].len; k++) 70 { 71 ll st=h[p^1].st[k]; 72 get(st); int pw=h[p^1].f[k]; 73 int x=c[j-1],y=c[j]; 74 memcpy(b,c,sizeof(b)); 75 if (a[i][j]>=0) 76 { 77 if (x&&y) 78 { 79 if (x==y) continue; 80 b[j-1]=b[j]=0; 81 for (int r=0; r<=m; r++) 82 if (b[r]==x) b[r]=y; 83 if (j==m) shift(); 84 h[p].push(put(),pw+a[i][j]); 85 continue; 86 } 87 else if (x||y) 88 { 89 int r=x+y; 90 if (a[i][j+1]>=0) 91 { 92 b[j]=r; b[j-1]=0; 93 h[p].push(put(),pw+a[i][j]); 94 } 95 if (a[i+1][j]>=0||(i==n&&!check(j-2))) 96 { 97 b[j]=0; b[j-1]=r; 98 if (j==m) shift(); 99 h[p].push(put(),pw+a[i][j]); 100 } 101 } 102 else { 103 if (a[i][j+1]>=0&&(a[i+1][j]>=0||(i==n&&!check(j-2)))) 104 { 105 b[j]=b[j-1]=m+1; 106 h[p].push(put(),pw+a[i][j]); 107 } 108 b[j]=b[j-1]=0; 109 if (j==m) shift(); 110 h[p].push(put(),pw); 111 } 112 } 113 else { 114 if (a[i][j]==-1) 115 { 116 if (j==m) shift(); 117 h[p].push(put(),pw); 118 continue; 119 } 120 int sd=check(j-2); 121 if (!(sd&1)&&a[i][j]==-3) continue; 122 if (sd&1&&a[i][j]==-2) continue; 123 if (j==m) shift(); 124 h[p].push(put(),pw); 125 } 126 } 127 } 128 129 int main() 130 { 131 //freopen("1.in","r",stdin); 132 //freopen("1.out","w",stdout); 133 while (scanf("%d%d",&n,&m)!=EOF) 134 { 135 memset(a,255,sizeof(a)); 136 for (int i=1; i<=n; i++) 137 { 138 scanf("%s",s+1); 139 for (int j=1; j<=m; j++) 140 { 141 int x=-1; 142 if (s[j]==‘#‘) x=-1; 143 else if (s[j]==‘W‘) x=-2; 144 else if (s[j]==‘L‘) x=-3; 145 else x=s[j]-‘0‘; 146 a[i][j]=x; 147 } 148 } 149 ans=1e9+7; 150 h[1].clr(); h[0].clr(); p=0; 151 for (int i=1; i<=m; i++) 152 if (a[1][i]>=0) 153 { 154 memset(b,0,sizeof(b)); b[i]=1; 155 h[0].push(put(),0); 156 } 157 for (int i=1; i<=n; i++) 158 for (int j=1; j<=m; j++) 159 { 160 p^=1; h[p].clr(); 161 dp(i,j); 162 // cout <<h[p].len<<" "<<i<<" "<<j<<endl; 163 } 164 for (int k=1; k<=h[p].len; k++) 165 { 166 get(h[p].st[k]); 167 int sd=check(m); 168 if (sd==1) ans=min(ans,h[p].f[k]); 169 } 170 if (ans==1000000007) puts("-1"); else printf("%d\n",ans); 171 } 172 }
标签:shift c++ 能力 插头dp else div int space check
原文地址:http://www.cnblogs.com/phile/p/6746224.html