洛谷 P2172 [国家集训队]部落战争 / YbtOJ「图论」第1章 二分图匹配 H. 部落战争 题解--zhengjun

思路

直接按照要求的走法可以建出一张 dag 图,发现就是跑一个最小路径覆盖,参见洛谷P2764题解

只需要用二分图匹配,每一次连接了一对匹配,相当于合并了两条路径(单个点也认为是路径),所以要让路径总数最小,就要让匹配的数量最大,由于是路径,所以每个点的入点和出点都最多只能连两条边。

代码

#include<bits/stdc++.h>
using namespace std;typedef long long ll;const int N=55,M=N*N*2,E=M*8;
int n,m,r,c,s,t,cnt,head[M],kk=1,dx[4],dy[4],dt,d[M],cur[M];struct edges{int to,c,nex;}edge[E];char a[N][N];
int id(int x,int y){return (x-1)*m+y;}
void add(int u,int v,int c){edge[++kk]={v,c,head[u]};head[u]=kk;edge[++kk]={u,0,head[v]};head[v]=kk;}
void cover(int st){dx[st]=r;dy[st]=-c;dx[st+1]=r;dy[st+1]=c;}
bool check(int x,int y){return x>0&&x<=n&&y>0&&y<=m&&a[x][y]=='.';}
bool bfs(){
	queue<int>q;memset(d,-1,sizeof d);cur[s]=head[s];d[s]=0;for(q.push(s);!q.empty();q.pop()){
		int u=q.front();for(int i=head[u],v;v=edge[i].to,i;i=edge[i].nex)
			if(d[v]==-1&&edge[i].c)q.push(v),d[v]=d[u]+1,cur[v]=head[v];
	}return ~d[t];
}
int dfs(int u,int lim=1e9){
	if(u==t)return lim;int flow=0;for(int i=cur[u],v;v=edge[i].to,i&&flow<lim;i=edge[i].nex){
		if(d[v]!=d[u]+1||!edge[i].c)continue;int f=dfs(v,min(lim-flow,edge[i].c));
		if(!f)d[v]=-1;edge[i].c-=f;edge[i^1].c+=f;flow+=f;
	}return flow;
}
int dinic(){int maxflow=0;while(bfs())maxflow+=dfs(s);return maxflow;}
int main(){
	scanf("%d%d%d%d",&n,&m,&r,&c);s=0;t=n*m*2+1;for(int i=1;i<=n;i++)scanf("%s",a[i]+1);
	if(r==c)dt=2,cover(0);else dt=4,cover(0),swap(r,c),cover(2);for(int i=1,ii,jj;i<=n;i++)for(int j=1;j<=m;j++)
		if(a[i][j])for(int k=0;k<dt;k++)ii=i+dx[k],jj=j+dy[k],check(ii,jj)&&(add(id(i,j),id(ii,jj)+n*m,1),0);
	for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)if(a[i][j]=='.')cnt++,add(s,id(i,j),1),add(id(i,j)+n*m,t,1);
	cout<<cnt-dinic();return 0;
}
posted @ 2022-06-28 08:31  A_zjzj  阅读(28)  评论(0编辑  收藏  举报