zoukankan      html  css  js  c++  java
  • [专题总结]初探插头dp

    彻彻底底写到自闭的一个专题。

    就是大型分类讨论,压行+宏定义很有优势。

    常用滚动数组+哈希表+位运算。当然还有轮廓线。

    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
    ",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
    ",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
    ",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
    ",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
    ",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
    ",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
    ",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
    ",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
    ",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
    ",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 }
    难写所以没压行
  • 相关阅读:
    asp.net微信内置浏览器下Session失效
    iOS 开发之路(WKWebView内嵌HTML5之图片上传) 五
    移动Web开发(二)
    iOS 开发之路(使用WKWebView加载Html5) 四
    iOS 开发之路(AES/DES加密实现) 三
    移动Web开发(一)
    iOS 开发之路(登陆验证调用WebService)二
    iOS 开发之路(登陆页键盘遮挡输入框问题)一
    canvas绘画常用方法
    JavaScript函数定义方式
  • 原文地址:https://www.cnblogs.com/hzoi-DeepinC/p/12003407.html
Copyright © 2011-2022 走看看