题意:给定一个网格,有一些格子是障碍不用管,剩余的是空地,你要用一些起点和终点在边界上的路径或环来完全覆盖掉空地,如果使用第一种,会付出1的代价,求最小代价,不能覆盖则输出-1。
现在看到网格而且数据范围小的基本上的是网络流黑白染色啊。。(废话你在做网络流的题啊)
其实这道题和之前那个只用环覆盖的很像,只不过这里可以用路径。之前我们考虑的是每个点都会被贯穿,也就说度数会是2,所以当初那道题我们用的是二分图跑费用流,但这里有路径,怎么办?
首先图的基本关系很简单,相邻点之间连普通的容量1,费用0就好了。然后我们考虑强制要让每个点被贯穿,黑白染色后,用下限去限制,S向黑点连下限为2的边,白点向T连下限为2的边。问题来了,有的方案是有路径的,路径的端点并没有被贯穿,这怎么整?
巧妙之处来了。对于端点,我们现在的问题是多了流量,怎么办?把它直接导去就完了。也就是说,我们对于边界上的黑点,向T连一条无下限,上限为1,费用为1的边,白色同理。为什么巧妙呢,这不但解决了端点度数为1的问题,而且一旦出现这种情况,就说明出现了路径,对答案产生贡献,我们再加上费用来记录,跑最小费用可行流就完了。答案记得除2,因为头尾算了两次。判断有无解看有无可行流就好了。
1 #include<bits/stdc++.h> 2 using namespace std; 3 inline int read(){ 4 int x=0,f=1; char a=getchar(); 5 while(a<'0' || a>'9') {if(a=='-') f=-1; a=getchar();} 6 while(a>='0' && a<='9') x=x*10+a-'0',a=getchar(); 7 return x*f; 8 } 9 #define INF 1e9 10 #define N 505 11 #define in ini 12 #define id(i,j) (((i)-1)*m+(j)) 13 const int dir[4][2]={0,1,0,-1,1,0,-1,0}; 14 int ans,n,m,head[N],cnt,d[N],a[N],p[N],S,SS,T,TT,TOT,in[N]; 15 char st[25][25]; 16 bool vis[N]; 17 queue<int>q; 18 struct edges{ 19 int fr,to,cap,flow,cost,next; 20 }e[2*N]; 21 22 inline void insert(int u,int v,int f,int c){ 23 e[cnt]=(edges){u,v,f,0,c,head[u]};head[u]=cnt++; 24 e[cnt]=(edges){v,u,0,0,-c,head[v]};head[v]=cnt++; 25 } 26 inline bool spfa(){ 27 memset(d,0x3f,sizeof(d)); 28 d[S]=0; a[S]=INF; q.push(S); 29 while(!q.empty()){ 30 int x=q.front(); q.pop(); vis[x]=0; 31 for(int i=head[x];i>=0;i=e[i].next) 32 if(d[e[i].to]>d[x]+e[i].cost && e[i].flow<e[i].cap){ 33 d[e[i].to]=d[x]+e[i].cost; p[e[i].to]=i; 34 a[e[i].to]=min(a[x],e[i].cap-e[i].flow); 35 if(!vis[e[i].to]) vis[e[i].to]=1,q.push(e[i].to); 36 } 37 } 38 return d[T]<INF; 39 } 40 inline void mincf(){ 41 ans+=a[T]*d[T]; TOT-=a[T]; 42 int u=T; 43 while(u!=S){ 44 e[p[u]].flow+=a[T]; 45 e[p[u]^1].flow-=a[T]; 46 u=e[p[u]].fr; 47 } 48 } 49 int main(){ 50 memset(head,-1,sizeof(head)); 51 while(scanf("%s",st[++n]+1)!=EOF); n--; 52 m=strlen(st[1]+1); 53 SS=0; TT=n*m+1; S=TT+1; T=TT+2; 54 for(int i=1;i<=n;i++) 55 for(int j=1;j<=m;j++){ 56 if(st[i][j]=='#') continue; 57 if((i+j)&1){ 58 if(i==1 || i==n || j==1 || j==m) insert(SS,id(i,j),1,1); 59 in[TT]+=2; in[id(i,j)]-=2; 60 }else{ 61 if(i==1 || i==n || j==1 || j==m) insert(id(i,j),TT,1,1); 62 in[SS]-=2; in[id(i,j)]+=2; 63 for(int k=0;k<4;k++){ 64 int tx=i+dir[k][0],ty=j+dir[k][1]; 65 if(tx<1 || tx>n || ty<1 || ty>m || st[tx][ty]=='#') continue; 66 insert(id(i,j),id(tx,ty),1,0); 67 } 68 } 69 } 70 insert(TT,SS,INF,0); 71 for(int i=SS;i<=TT;i++){ 72 if(in[i]>0) insert(S,i,in[i],0),TOT+=in[i]; 73 if(in[i]<0) insert(i,T,-in[i],0); 74 } 75 while(spfa()) mincf(); 76 if(!TOT) printf("%d\n",ans/2); 77 else puts("-1"); 78 return 0; 79 }