BZOJ 4213 贪吃蛇 上下界费用流 网络流

https://darkbzoj.cf/problem/4213

https://www.cnblogs.com/DaD3zZ-Beyonder/p/5733326.html 题目描述 dbzoj又崩了存个代码

 

一条对答案有贡献的蛇一定有两个点在边界上且这两个点都只连了一条边,这条蛇上的其他点一定都连了两条边。

把格子按照如国际象棋棋盘的样式黑白填充,那么一条蛇是一条链(或者环),链上的点黑白交错。

对每个白点匹配两个相邻的黑点(黑白填充是为了方便建图(类似于二分图匹配)),只能匹配一个相邻点的点的数量的最小值/2就是最少的有贡献的蛇的数量。

 

所以建图为

s -> 白 流量2 费用0 上下界2

黑 -> t 流量2 费用0 上下界2

白 -> 相邻黑 流量1费用0 

边缘白 -> t 流量1费用1

s -> 边缘黑 流量1费用1

 

改造成上下界的就可以了。同这道题→BZOJ2055 80人环游世界

 
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<queue>
 7 using namespace std;
 8 #define LL long long
 9 const int maxn=60100;
10 int n=0,m=0,mx=0,ss=0,tt=0,S=0,T=0,z;
11 char ch[20][20];
12 struct nod{
13     int y,v,co,nex;
14 }e[maxn];
15 int head[400]={},tot=1;
16 int d[400]={},id[20][20]={},ans=0;
17 void init(int x,int y,int v,int co){
18     e[++tot].y=y;e[tot].v=v;e[tot].co=co;e[tot].nex=head[x];head[x]=tot;
19     e[++tot].y=x;e[tot].v=0;e[tot].co=-co;e[tot].nex=head[y];head[y]=tot;
20 }
21 int dis[400];bool vis[400]={};
22 queue<int>q;
23 bool SPFA(){
24     memset(dis,31,sizeof(dis));
25     memset(vis,0,sizeof(vis));
26     int tn=dis[1];
27     q.push(S);dis[S]=0;vis[S]=1;
28     while(!q.empty()){
29         int x=q.front(),y;q.pop();vis[x]=0;
30         for(int i=head[x];i;i=e[i].nex){
31             y=e[i].y;
32             if(e[i].v>0&&dis[y]>dis[x]+e[i].co){
33                 dis[y]=dis[x]+e[i].co;
34                 if(!vis[y]){vis[y]=1;q.push(y);}
35             }
36         }
37     }
38     return dis[T]!=tn;
39 }
40 int dfs(int x,int flo){
41     if(x==T){
42         ans+=dis[x]*flo;return flo;
43     }vis[x]=1;
44     int liu=0,tv,y;
45     for(int i=head[x];i;i=e[i].nex){
46         y=e[i].y;
47         if(vis[y]||dis[y]!=dis[x]+e[i].co||e[i].v<=0)continue;
48         tv=dfs(y,min(flo-liu,e[i].v));
49         liu+=tv;e[i].v-=tv;e[i^1].v+=tv;
50         if(liu==flo)break;
51     }
52     return liu;
53 }
54 bool Check(int x,int y){if(x>=1&&x<=n&&y>=1&&y<=m&&ch[x][y]!='#')return 1;return 0;}
55 void Buildedge(){
56     for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) id[i][j]=(i-1)*m+j;
57     for(int i=1;i<=n;i++){
58         for(int j=1;j<=m;j++){
59             if(ch[i][j]=='#')continue;
60             if((i+j)&1){
61                 d[ss]-=2;d[id[i][j]]+=2;
62                 if(Check(i-1,j))init(id[i][j],id[i-1][j],1,0);
63                 if(Check(i,j-1))init(id[i][j],id[i][j-1],1,0);
64                 if(Check(i+1,j))init(id[i][j],id[i+1][j],1,0);
65                 if(Check(i,j+1))init(id[i][j],id[i][j+1],1,0);
66             }
67             else {d[tt]+=2;d[id[i][j]]-=2;}        
68         }
69     }
70     for(int i=1;i<=tt;i++){
71         if(d[i]>0)init(S,i,d[i],0);
72         if(d[i]<0) init(i,T,-d[i],0);
73     }
74     for(int i=1;i<=n;i++){
75         for(int j=1;j<=m;j++){
76             if(i==1||j==1||i==n||j==m){
77                 if(ch[i][j]=='#')continue;
78                 if((i+j)&1)init(id[i][j],tt,1,1);
79                 else init(ss,id[i][j],1,1);
80             }
81         }
82     }
83     init(tt,ss,mx,0);
84 }
85 int main(){
86     //freopen("a.in","r",stdin);
87     n=1;
88     while(~scanf("%s",ch[n]+1))++n; 
89     n--;
90     for(int i=1;;++i){m=i-1;if(ch[1][i]!='.'&&ch[1][i]!='#')break;}
91     mx=n*m;ss=mx+1;tt=ss+1;S=tt+1;T=S+1;
92     Buildedge();
93     while(SPFA()){memset(vis,0,sizeof(vis));dfs(S,mx);}
94     int f=1;
95     for(int i=head[S];i;i=e[i].nex)if(e[i].v)f=0;
96     if(f)printf("%d\n",ans/2);
97     else printf("-1\n");
98     return 0;
99 }
View Code

 

posted @ 2018-05-03 09:06  鲸头鹳  阅读(324)  评论(0编辑  收藏  举报