UVA1184 Air Raid(最小割)

UVA1184 Air Raid(最小割)

传送门

最小割又忘记了,菜!

题意:给一个无向图,求最少多少不相交的链经过所有的点(单独一个点也算链)。

题解:

首先要想到题目的一个关键,每个点被链经过以后最多能免费携带一个没被经过的其他点。如一条:1-4-3-5,第一个点是买的,4是1免费带的,3是4免费带的,5是3免费带的。

所以图可以转成二分图,那么最大匹配就是最多能免费带多少,所以答案就是所有点数减去最大匹配

#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int N=507;
const int M=1e5+7;
const int inf=1e9;
int t,n,m,S,T;
int h[N],e[M],f[M],ne[M],tot;
int d[N],cur[N];
void init(){
	memset(h,-1,sizeof(h));
	tot=0;
}
void add(int u,int v,int z){
	e[tot]=v;
	f[tot]=z;
	ne[tot]=h[u];
	h[u]=tot++;
	e[tot]=u;
	f[tot]=0;
	ne[tot]=h[v];
	h[v]=tot++;
}
bool bfs(){
	queue<int>sa;
	memset(d,-1,sizeof(d));
	sa.push(S);
	d[S]=0;
	cur[S]=h[S];
	while(!sa.empty()){
		int p=sa.front();
		sa.pop();
		for(int i=h[p];~i;i=ne[i]){
			int to=e[i];
			if(f[i]>0&&d[to]==-1){
				d[to]=d[p]+1;
				cur[to]=h[to];
				if(to==T){
					return true;
				}
				sa.push(to);
			}
		}
	}
	return false;
}
int dfs(int p,int now){
	if(p==T)return now;
	int sum=0;
	for(int i=cur[p];~i&&now>sum;i=ne[i]){
		int to=e[i];
		cur[p]=i;
		if(d[to]==d[p]+1&&f[i]>0){
			int lin=dfs(to,min(f[i],now-sum));
			if(lin==0){
				d[to]=-1;
			}
			else{
				f[i]-=lin;
				f[i^1]+=lin;
				sum+=lin;
			}
		}
	}
	return sum;
}
int dinic(){
	int fw=0;
	while(bfs()){
		fw+=dfs(S,inf);
	}
	return fw;
}
int main(){
	scanf("%d",&t);
	while(t--){
		init();
		scanf("%d%d",&n,&m);
		S=n*2+1;
		T=n*2+2;
		for(int i=1;i<=m;i++){
			int u,v;
			scanf("%d%d",&u,&v);
			add(u,v+n,inf);
		}
		for(int i=1;i<=n;i++){
			add(S,i,1);
			add(i+n,T,1);
		}
		int res=dinic();
		printf("%d
",n-res);
	}
}
原文地址:https://www.cnblogs.com/whitelily/p/14615930.html