彻彻底底写到自闭的一个专题。
就是大型分类讨论,压行+宏定义很有优势。
常用滚动数组+哈希表+位运算。当然还有轮廓线。
Formula 1:
经过所有格子的哈密顿回路数。
每个非障碍点必须有且仅有2个插头(含上下左右)。
若左上都没有,那么新建两个插头1和2。
若左上只有一个插头,那么它就向右下方向之一延伸。
若左上都有,那么不建新插头。
如果是左1上2,那么就是形成了一条回路,当且仅当在全图右下角更新答案。
如果都是1,那么就要把右边的两个2改成一对插头,就是把靠右的一个1插头匹配的2插头改为1。
都是2同理。
如果是左2上1,那么就是链接了两个路径,两个插头抵消。
1 #include<cstdio> 2 #define cri const register int 3 int bl[13][13],n,m,now,last=1,ln,lm,fn,fm,r[3]={0,1,-1};long long ans; 4 int read(){ 5 register char ch=getchar(); 6 while(ch!='*'&&ch!='.')ch=getchar(); 7 return ch=='*'; 8 } 9 struct hash{ 10 int fir[54321],l[54321],to[54321],cnt;long long v[54321]; 11 void clear(){ 12 for(int i=0;i<54321;++i)to[i]=-1,fir[i]=v[i]=0;cnt=0; 13 } 14 long long &operator[](cri pos){ 15 int i; 16 for(i=fir[pos%54321];i&&to[i]!=pos;i=l[i]); 17 if(!i)l[++cnt]=fir[pos%54321],to[cnt]=pos,fir[pos%54321]=i=cnt; 18 return v[i]; 19 } 20 }f[2]; 21 inline int find(cri st,cri p){return st>>(p-1<<1)&3;} 22 inline void set(int &st,cri p,cri k){st&=~(3<<(p-1<<1));st|=k<<(p-1<<1);} 23 inline int get(cri st,cri p){ 24 int dirc=(find(st,p)==1)?1:-1; 25 for(int i=p,pl=find(st,i),cnt=r[pl];i&&i<=m+1;pl=find(st,i+=dirc),cnt+=r[pl]) 26 if(cnt==0)return i; 27 } 28 int main(){ 29 scanf("%d%d",&n,&m); 30 for(int i=1;i<=n;++i)for(int j=1;j<=m;++j){ 31 bl[i][j]=read(); 32 if(!bl[i][j])ln=i,lm=j; 33 if(!fn&&!bl[i][j])fn=i,fm=j; 34 }f[0][0]=1; 35 for(int i=1;i<=n;++i)bl[i][m+1]=1; 36 for(int i=1;i<=m;++i)bl[n+1][i]=1; 37 for(int i=fn;i<=n;++i){ 38 for(int j=(i==fn)?fm:1;j<=m;++j){ 39 last^=1;now^=1; f[now].clear(); 40 for(int k=1;k<=f[last].cnt;++k){ 41 int st=f[last].to[k],p1=find(st,j),p2=find(st,j+1); 42 long long v=f[last].v[k];//printf("%d %d %d %d %d %lld\n",i,j,st,p1,p2,v); 43 if(bl[i][j]&&(p1||p2))continue; 44 if(bl[i][j])f[now][st]+=v; 45 else if(!p1&&!p2){if(!bl[i][j+1]&&!bl[i+1][j])set(st,j,1),set(st,j+1,2),f[now][st]+=v;} 46 else if(p1&&!p2){ 47 if(!bl[i+1][j])f[now][st]+=v;//,printf("---%d %d %lld %lld\n",i,j,v,f[now][st]); 48 if(!bl[i][j+1])set(st,j+1,p1),set(st,j,0),f[now][st]+=v; 49 } 50 else if(!p1&&p2){ 51 if(!bl[i][j+1])f[now][st]+=v; 52 if(!bl[i+1][j])set(st,j,p2),set(st,j+1,0),f[now][st]+=v; 53 } 54 else if(p1==1&&p2==2){if(i==ln&&j==lm)ans+=v;} 55 else if(p2==1&&p1==2)set(st,j,0),set(st,j+1,0),f[now][st]+=v; 56 else if(p1==1&&p2==1)set(st,get(st,j+1),1),set(st,j,0),set(st,j+1,0),f[now][st]+=v; 57 else if(p1==2&&p2==2)set(st,get(st,j),2),set(st,j,0),set(st,j+1,0),f[now][st]+=v; 58 } 59 } 60 for(int i=1;i<=f[now].cnt;++i)f[now].to[i]<<=2; 61 } 62 printf("%lld\n",ans); 63 }
CITY
和上面同理,只不过限制了插头方向。
1 #include<cstdio> 2 #define int long long 3 #define mod 54321 4 int n,m,bl[15][15],ref[129],fn,fm,ln,lm,last=1,now,tf[3]={0,1,-1};long long ans; 5 int read(){ 6 register char ch=getchar(); 7 while(ch!='.'&&ch!='#'&&ch!='-'&&ch!='|')ch=getchar(); 8 return ref[ch]; 9 } 10 struct hash{ 11 int fir[mod],l[mod],to[mod],cnt;long long v[mod]; 12 void clear(){for(int i=0;i<mod;++i)fir[i]=v[i]=0,to[i]=-1;cnt=0;} 13 long long &operator[](int p){ 14 int i; 15 for(i=fir[p%mod];i&&to[i]!=p;i=l[i]); 16 if(!i)l[++cnt]=fir[p%mod],fir[p%mod]=i=cnt,to[cnt]=p; 17 return v[i]; 18 } 19 }f[2]; 20 int find(int st,int p){return st>>(p-1<<1)&3;} 21 void set(int &st,int p,int k){st&=~(3<<(p-1<<1));st|=k<<(p-1<<1);} 22 void reset(int &st,int p){ 23 for(int i=p,pl=find(st,i),di=tf[find(st,p)],cnt=di;i&&i<=m+1;i+=di,pl=find(st,i),cnt+=tf[pl]) 24 if(!cnt){set(st,i,pl==1?2:1);return;} 25 } 26 main(){ 27 scanf("%lld%lld",&n,&m);ref['#']=3;ref['-']=1;ref['|']=2; 28 for(int i=1;i<=n;++i)for(int j=1;j<=m;++j){ 29 bl[i][j]=read(); 30 if(!bl[i][j])ln=i,lm=j; 31 if(!bl[i][j]&&!fn)fn=i,fm=j; 32 } 33 f[0][0]=1; 34 for(int i=1;i<=n;++i)bl[i][m+1]=3; 35 for(int i=1;i<=m;++i)bl[n+1][i]=3; 36 for(int i=fn;i<=n;++i){ 37 for(int j=(i==fn?fm:1);j<=m;++j){ 38 last^=1;now^=1;f[now].clear(); 39 for(int k=1;k<=f[last].cnt;++k){ 40 int st=f[last].to[k],p1=find(st,j),p2=find(st,j+1);long long v=f[last].v[k];//printf("%d %d %d %d %d %lld\n",i,j,st,p1,p2,v); 41 if(((bl[i][j]&1)&&p2)||((bl[i][j]&2)&&p1))continue; 42 if(bl[i][j]==3){if(!p1&&!p2)f[now][st]+=v;continue;} 43 if(bl[i][j]==2){if((!(bl[i+1][j]&1))&&p2&&!p1)set(st,j+1,0),set(st,j,p2),f[now][st]+=v;continue;} 44 if(bl[i][j]==1){if((!(bl[i][j+1]&2))&&p1&&!p2)set(st,j,0),set(st,j+1,p1),f[now][st]+=v;continue;} 45 if(!p1&&!p2){if(!(bl[i][j+1]&2)&&!(bl[i+1][j]&1))set(st,j,1),set(st,j+1,2),f[now][st]+=v;} 46 else if(p1&&!p2){ 47 if(!(bl[i+1][j]&1))f[now][st]+=v; 48 if(!(bl[i][j+1]&2))set(st,j,0),set(st,j+1,p1),f[now][st]+=v; 49 } 50 else if(p2&&!p1){ 51 if(!(bl[i][j+1]&2))f[now][st]+=v; 52 if(!(bl[i+1][j]&1))set(st,j+1,0),set(st,j,p2),f[now][st]+=v; 53 } 54 else if(p1==1&&p2==2){if(i==ln&&j==lm)ans+=v;} 55 else if(p2==1&&p1==2)set(st,j,0),set(st,j+1,0),f[now][st]+=v; 56 else if(p1==1&&p2==1)reset(st,j+1),set(st,j,0),set(st,j+1,0),f[now][st]+=v; 57 else if(p1==2&&p2==2)reset(st,j),set(st,j,0),set(st,j+1,0),f[now][st]+=v; 58 } 59 } 60 for(int j=1;j<=f[now].cnt;++j)f[now].to[j]<<=2; 61 } 62 printf("%lld\n",ans); 63 }
邮递员
依旧同理。注意n或m=1。
1 #include<cstdio> 2 #define hash_mod 54321 3 #define int_mod 100000000000000ll 4 #define cri const register int 5 int n,m; 6 struct gj{ 7 long long x[5]; 8 inline void clear(){x[0]=x[1]=x[2]=x[3]=x[4]=0;} 9 inline void print(){ 10 int i; 11 for(i=4;i>=0;--i)if(x[i]){printf("%lld",x[i]);break;} 12 for(i--;i>=0;--i)printf("%014lld",x[i]);puts(""); 13 } 14 inline void operator+=(const gj &b){ 15 for(int i=4;i>=0;--i)x[i]+=b.x[i]; 16 for(int i=0;i<=3;++i)x[i+1]+=x[i]/int_mod,x[i]%=int_mod; 17 } 18 }ans; 19 struct hash_map{ 20 int fir[54321],l[54321],to[54321],cnt;gj v[54321]; 21 void clear(){ 22 for(int i=0;i<54321;++i)fir[i]=0,v[i].clear(),to[i]=-1; 23 cnt=0; 24 } 25 gj &operator[](const int key){ 26 int pos=key%hash_mod,i; 27 for(i=fir[pos];to[i]!=key&&i;i=l[i]); 28 if(!i)to[++cnt]=key,l[cnt]=fir[pos],i=fir[pos]=cnt,v[cnt].clear(); 29 return v[i]; 30 } 31 }hash[2]; 32 inline int find(cri st,cri pos){return st>>(pos-1<<1)&3;} 33 inline int get(cri st,cri pos){ 34 int cnt=0,dirc=(find(st,pos)==1)?1:-1; 35 for(int i=pos,plug=find(st,pos);i&&i<=m+1;plug=find(st,i+=dirc)){ 36 if(plug==1)cnt++;else if(plug==2)cnt--; 37 if(cnt==0)return i; 38 } 39 return -1; 40 } 41 inline void set(int &st,cri pos,cri kind){ 42 st|=3<<(pos-1<<1);st^=3<<(pos-1<<1); 43 st|=kind<<(pos-1<<1); 44 } 45 void DP(cri x,cri y){ 46 int now=(x-1)*m+y&1,last=now^1,tot=hash[last].cnt; 47 hash[now].clear(); 48 for(int i=1;i<=tot;++i){ 49 int st=hash[last].to[i],plug1=find(st,y),plug2=find(st,y+1); 50 gj v=hash[last].v[i];//printf("%d %d %d %d %d ",x,y,st,plug1,plug2);v.print(); 51 if(get(st,y)==-1||get(st,y+1)==-1)continue; 52 if(!plug1&&!plug2){if(y!=m&&x!=n)set(st,y,1),set(st,y+1,2),hash[now][st]+=v;} 53 else if(plug1&&!plug2){ 54 if(x!=n)hash[now][st]+=v; 55 if(y!=m)set(st,y,0),set(st,y+1,plug1),hash[now][st]+=v; 56 } 57 else if(!plug1&&plug2){ 58 if(y!=m)hash[now][st]+=v; 59 if(x!=n)set(st,y,plug2),set(st,y+1,0),hash[now][st]+=v; 60 } 61 else if(plug1==1&&plug2==2){if(x==n&&y==m)ans+=v;} 62 else if(plug1==2&&plug2==1)set(st,y,0),set(st,y+1,0),hash[now][st]+=v; 63 else if(plug1==1&&plug2==1) 64 set(st,get(st,y+1),1),set(st,y,0),set(st,y+1,0),hash[now][st]+=v; 65 else if(plug1==2&&plug2==2) 66 set(st,get(st,y),2),set(st,y,0),set(st,y+1,0),hash[now][st]+=v; 67 }//printf("%d--%d--%d\n",x,y,hash[now].cnt); 68 } 69 int main(){ 70 scanf("%d%d",&n,&m); 71 hash[0].clear();hash[0][0].x[0]=1; 72 if(n==1||m==1){printf("1");return 0;} 73 if(n<m)n^=m,m^=n,n^=m; 74 for(int i=1;i<=n;++i){ 75 for(int j=1;j<=m;++j)DP(i,j); 76 if(i!=n){ 77 int now=(i*m)&1,tot=hash[now].cnt; 78 for(int i=1;i<=tot;++i)hash[now].to[i]<<=2; 79 } 80 } 81 if(ans.x[0]==0){puts("0");return 0;} 82 ans+=ans;ans.print(); 83 }
地板
这个插头不太一样。
对于一个L型,其实只有转弯前和转弯后两种状态。分别做1,2。
空格的话,可以把这个点作为拐角,往右下两个方向延伸出两个已经拐弯的插头。
如果只有一个1插头,那么可以选择转弯与否。
如果两个1插头碰在一起,那么它们就在这里转弯,互相抵消。
如果只有一个2插头,那么就延伸就好了。
1 #include<cstdio> 2 #include<cstring> 3 using namespace std; 4 #define mod 20110520 5 #define ad(a,b) add(dp[nx][set(set(st,j,a),j+1,b)],v) 6 void add(int &a,int b){a+=b;if(a>mod)a-=mod;} 7 int n,m,dp[2][8048577];char s[111][111];bool a[111][111]; 8 int find(int st,int num){return st>>num*2-2&3;} 9 int set(int st,int num,int v){return st^st&3<<num*2-2^v<<num*2-2;} 10 int main(){ 11 scanf("%d%d",&n,&m); 12 for(int i=1;i<=n;++i)scanf("%s",s[i]+1); 13 if(n<m){ 14 for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)a[j][i]=s[i][j]=='_'; 15 n^=m^=n^=m; 16 }else for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)a[i][j]=s[i][j]=='_'; 17 int nw=0,nx=1;dp[1][0]=1; 18 for(int i=1;i<=n;++i){ 19 for(int j=1;j<=m;++j){ 20 nw^=1;nx^=1; 21 for(int st=0;st<1<<m*2+2;++st)if(dp[nw][st]){ 22 int l=find(st,j),u=find(st,j+1),v=dp[nw][st];dp[nw][st]=0; 23 if(!a[i][j]){if(l==0&&u==0)ad(0,0);continue;} 24 if(l==0&&u==0)ad(2,2),ad(1,0),ad(0,1); 25 else if(l==1&&u==0)ad(0,1),ad(2,0); 26 else if(l==0&&u==1)ad(1,0),ad(0,2); 27 else if(l==1&&u==1)ad(0,0); 28 else if(l==0&&u==2)ad(0,0),ad(2,0); 29 else if(l==2&&u==0)ad(0,0),ad(0,2); 30 } 31 } 32 nw^=1;nx^=1; 33 for(int st=0;st<1<<m*2;++st)dp[nx][st<<2]=dp[nw][st]; 34 for(int st=0;st<1<<m*2+2;++st)dp[nw][st]=0; 35 }printf("%d\n",dp[nx][0]); 36 }
标识设计
题意补充:笔画的宽度一定是1,棋盘不用占满,L型不能旋转。
因为不能旋转,所以只有一种插头。
但是不能占满,这个好说,只不过多了一种如果这个格子是空格的话也可以不增加新插头。
然后就退化一下上一题的代码,不过区分一下已经写了几个L就行。
1 #include<cstdio> 2 #include<cstring> 3 using namespace std; 4 int dp[2][16666],n,m,w[111][7],stc,cts[16666],ans=-12345678,nw,nx=1; 5 int find(int st,int num){return st>>num*2&3;} 6 void sch(int al,int st){if(al==m+1)cts[++stc]=st;else for(int i=0;i<=2;++i)sch(al+1,st|i<<al*2);} 7 int set(int st,int num,int v){return st^st&3<<num*2^v<<num*2;} 8 void maxi(int &a,int b){if(a<b)a=b;} 9 int rmat(int st,int p){for(int i=p+1;;++i)if(find(st,i)==2)return st-(1<<i*2);} 10 int lmat(int st,int p){for(int i=p-1;;--i)if(find(st,i)==1)return st+(1<<i*2);} 11 #define upd(a,b) maxi(dp[nx][set(set(st,j-1,a),j,b)],v) 12 int main(){ 13 scanf("%d%d",&n,&m);memset(dp,0xa0,sizeof dp); 14 for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)scanf("%d",&w[i][j]); 15 dp[nx][0]=0;sch(0,0); 16 for(int i=1;i<=n;++i){ 17 for(int j=1;j<=m;++j){ 18 nw^=1;nx^=1;memset(dp[nx],0xa0,sizeof dp[nx]); 19 for(int p=1,st;p<=stc;++p)if(dp[nw][st=cts[p]]>=-12345678){ 20 int p1=find(st,j-1),p2=find(st,j),v=dp[nw][st]+w[i][j]; 21 if(p1==0&&p2==0)upd(1,2),maxi(dp[nx][st],dp[nw][st]); 22 if(p1==1&&p2==2)if(set(set(st,j-1,0),j,0)==0)maxi(ans,v); 23 if(p1==2&&p2==1)upd(0,0); 24 if((p1^p2)==2)upd(0,2),upd(2,0); 25 if((p1^p2)==1)upd(0,1),upd(1,0); 26 if(p1==1&&p2==1)maxi(dp[nx][rmat(set(set(st,j-1,0),j,0),j)],v); 27 if(p1==2&&p2==2)maxi(dp[nx][lmat(set(set(st,j-1,0),j,0),j)],v); 28 } 29 } 30 nw^=1;nx^=1;memset(dp[nx],0xa0,sizeof dp[nx]); 31 for(int p=1,st;p<=stc;++p)if(cts[p]<1<<m<<m)dp[nx][cts[p]<<2]=dp[nw][cts[p]]; 32 }printf("%d\n",ans); 33 }
Park II
毒瘤界的巅峰。
理论上有3个插头,16种情况,但是情况很多重复,所以可以压成9类。
因为这一题是路径而不是回路,而且也不用占满。
为了处理路径的问题,需要引进一种新的插头,就是一端为路径的端点,另一端在轮廓线上的插头,学习LadyLex称之为独立插头3。
所有插头合并情况如下:
1,两个空格:这个格子可以不放,也可以作为拐角放一对12插头,也可以作为路径端点在右下方向之一放一个3插头。
2,两个1/2:与回路的题做法一致。
3,两个3:如果没有其它插头,那么你已经让两个自由端联通了,如果不存在其它插头,那么就可以更新答案。
4,左1上2:在回路题里这样会形成回路,但是路径题不允许回路,所以不做操作。(也就是在代码里不用写出来这种情况)
5,左2上1:与回路的题做法一致。
6,只有一个插头:另一个可以向右下方向之一转弯。
7,只有一个3插头:它可以结束了,作为路径端点,这样的话如果没有其它插头就可以更新答案了。
8,只有一个1/2插头:它可以结束了,作为路径端点,这样的话与1/2配对的2/1插头应该变成孤立的3插头。
9,有一个1/2插头,另一个是3插头:它们匹配了,这样的话与1/2配对的2/1插头应该变成孤立的3插头。
没有其它情况了。
如果宏定义+压行足够优秀,这道题不一定会比前面的题长。
1 #include<cstdio> 2 #include<cstring> 3 using namespace std; 4 void maxi(int &a,int b){if(a<b)a=b;} 5 int set(int st,int p,int v){return st^st&3<<p*2^v<<p*2;} 6 int get(int st,int p){return st>>p*2&3;} 7 int mat(int st,int p,int v,int d,int g,int c=1){ 8 for(;;p+=d)if(get(st,p)==g+1){c--;if(!c)return st+(v-g-1<<p*2);} 9 else if(get(st,p)==(g^1)+1)c++; 10 } 11 int dp[2][266666],w,n,m,nx,nw=1,ans,c[4],ac[266666]; 12 #define up(a,b) maxi(dp[nx][set(set(st,j-1,a),j,b)],v) 13 #define cl set(set(st,j-1,0),j,0) 14 int main(){ 15 scanf("%d%d",&n,&m); 16 memset(dp,0xa0,sizeof dp);dp[nx][0]=0; 17 for(int i=1;i<=n;++i){ 18 for(int j=1;j<=m;++j){ 19 nw^=1;nx^=1;memset(dp[nx],0xa0,sizeof dp[nx]);scanf("%d",&w); 20 for(int st=0;st<1<<m*2+2;++st)if(dp[nw][st]>-12345678){ 21 int p1=get(st,j-1),p2=get(st,j),v=dp[nw][st]+w; 22 for(int q=0;q<4;++q)c[q]=0;c[p1]++;c[p2]++; 23 if(c[0]==2)up(1,2),up(3,0),up(0,3),maxi(dp[nx][st],v-w); 24 if(c[1]==2)maxi(dp[nx][mat(cl,j,1,1,1)],v); 25 if(c[2]==2)maxi(dp[nx][mat(cl,j,2,-1,0)],v); 26 if(c[3]==2)if(!cl)maxi(ans,v); 27 if(p1==2&p2==1)up(0,0); 28 if(c[0]==1)up(p1|p2,0),up(0,p1|p2); 29 if(c[0]&c[3])if(!cl)maxi(ans,v); 30 if(c[1]&(c[0]|c[3]))maxi(dp[nx][mat(cl,j,3,1,1)],v); 31 if(c[2]&(c[0]|c[3]))maxi(dp[nx][mat(cl,j,3,-1,0)],v); 32 } 33 } 34 nx^=1;nw^=1;memset(dp[nx],0xa0,sizeof dp[nx]); 35 for(int st=0;st<1<<m*2;++st)dp[nx][st<<2]=dp[nw][st]; 36 }printf("%d\n",ans); 37 }
游览计划
插头dp的话不是很好做,开5种插头记录联通块就行了。
我没有这么写,我写的是最小斯坦纳树。
好像没听过很高端?实际上就是dp。
dp[i][j][st]表式包含(i,j)这个点的一个联通块所覆盖的景点集合为st(状态压缩)。
考虑转移:
首先如果(i,j)就是景点,编号为k,那么dp[i][j][k]=0;
这个点往四周扩展:dp[x][y][st]=min(dp[i][j][st]+w[x][y])
这个点的子集合并:dp[i][j][st]=min(dp[i][j][s1]+dp[i][j][s2]-w[i][j]),其中s1与s2的并集为st。
没了。
但是第一个转移出环了。用原来B组题里的那个SPFA解决循环dp就好了。
记录转移点回溯输出方案。
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 using namespace std; 5 const int xx[]={0,0,1,-1},yy[]={1,-1,0,0}; 6 #define tx x+xx[i] 7 #define ty y+yy[i] 8 int w[11][11],n,m,k=1,dp[11][11][1025],pre[11][11][1025],qx[1111],qy[1111],iq[11][11],v[11][11]; 9 void SPFA(int st,int t=0){ 10 for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)if(dp[i][j][st]<999999)qx[++t]=i,qy[t]=j,iq[i][j]=1; 11 for(int h=1,x,y;x=qx[h],y=qy[h],iq[x][y]=0,h<=t;++h)for(int i=0;i<4;++i) 12 if(tx&&ty&&tx<=n&&ty<=m&&dp[tx][ty][st]>dp[x][y][st]+w[tx][ty]){ 13 dp[tx][ty][st]=dp[x][y][st]+w[tx][ty];pre[tx][ty][st]=x<<20|y<<10|st; 14 if(!iq[tx][ty])iq[qx[++t]=tx][qy[t]=ty]=1; 15 } 16 } 17 void dfs(int x,int y,int st){ 18 v[x][y]=1;int px=pre[x][y][st]>>20,py=pre[x][y][st]>>10&1023,pst=pre[x][y][st]&1023; 19 if(!pre[x][y][st])return; 20 dfs(px,py,pst);if(x==px&&y==py)dfs(px,py,st^pst); 21 } 22 int main(){ 23 scanf("%d%d",&n,&m);memset(dp,0x3f,sizeof dp); 24 for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)scanf("%d",&w[i][j]); 25 for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)if(!w[i][j])dp[i][j][k]=0,k<<=1; 26 for(int st=1;st<k;++st){ 27 for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)for(int s=st&st-1;s;s=s-1&st) 28 if(dp[i][j][st]>dp[i][j][s]+dp[i][j][st^s]-w[i][j]) 29 dp[i][j][st]=dp[i][j][s]+dp[i][j][st^s]-w[i][j],pre[i][j][st]=i<<20|j<<10|s; 30 SPFA(st); 31 } 32 for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)if(!w[i][j]){ 33 dfs(i,j,k-1);printf("%d\n",dp[i][j][k-1]); 34 for(int i=1;i<=n;++i,puts(""))for(int j=1;j<=m;++j)putchar(w[i][j]?(v[i][j]?'o':'_'):'x'); 35 return 0; 36 } 37 }