2018.10.11【POJ1422】Air Raid(最小路径覆盖)

本文探讨了如何将最小路径覆盖问题转化为网络流问题,并通过二分图最大匹配算法求解。介绍了具体实现过程,包括边的添加、最大流算法(Dinic算法)的运用,以及如何计算最终结果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

传送门


解析:

其实最小路径覆盖没有什么特别的,还是一个匹配问题,我们将这个问题转化成网络流。

发现我们其实初始可以将每个点都放上一个伞兵,这样伞兵个数显然是 n n n,然后我们发现每一个点的伞兵可以由经过他前一个点的伞兵代替,于是我们将这条路径标记一下。

发现每个点最多在所有入边里面产生一个匹配,在所有出边里面产生一个匹配。

我们将每一个点拆成两个,按照边的出入关系建图,跑二分图最大匹配就行了。


代码:

#include<iostream>
#include<cstdio>
#include<cctype>
#include<cstring>
#include<queue>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const

inline int getint(){
	re int num;
	re char c;
	while(!isdigit(c=gc()));num=c^48;
	while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48);
	return num;
}

inline void outint(int a){
	static char ch[13];
	if(a==0)pc('0');
	while(a)ch[++ch[0]]=a-a/10*10,a/=10;
	while(ch[0])pc(ch[ch[0]--]^48);
}

cs int N=250,M=20004,INF=0x3f3f3f3f;
cs int S=0,T=249;
int last[N],nxt[M<<1],to[M<<1],ecnt;
int cap[M<<1];
inline void addedge(int u,int v,int val){
	nxt[++ecnt]=last[u],last[u]=ecnt,to[ecnt]=v,cap[ecnt]=val;
	nxt[++ecnt]=last[v],last[v]=ecnt,to[ecnt]=u,cap[ecnt]=0;
}

int lev[N],cur[N];
inline bool BFS(){
	memset(lev,-1,sizeof lev);
	queue<int> q;
	q.push(S),lev[S]=0,cur[S]=last[S];
	while(!q.empty()){
		int u=q.front();
		q.pop();
		for(int re e=last[u],v=to[e];e;v=to[e=nxt[e]]){
			if(cap[e]&&lev[v]==-1){
				lev[v]=lev[u]+1;
				if(v==T)return true;
				cur[v]=last[v];
				q.push(v);
			}
		}
	}
	return false;
}

inline int Dinic(cs int &u,cs int &flow){
	if(u==T)return flow;
	int ans=0;
	for(int &e=cur[u],v=to[e];e;v=to[e=nxt[e]]){
		if(cap[e]&&lev[v]>lev[u]){
			int delta=Dinic(v,min(flow-ans,cap[e]));
			if(delta){
				cap[e]-=delta;
				cap[e^1]+=delta;
				ans+=delta;
				if(ans==flow)return flow;
			}
		}
	}
	return ans;
}

inline int maxflow(){
	int ans=0;
	while(BFS())ans+=Dinic(S,INF);
	return ans;
}

inline void init(){
	ecnt=1;
	memset(last,0,sizeof last);
}

int n,m,t;
signed main(){
	t=getint();
	while(t--){
		init();
		n=getint();
		m=getint();
		for(int re i=1;i<=m;++i){
			int u=getint(),v=getint();
			addedge(u,v+120,1);
		}
		for(int re i=1;i<=n;++i)addedge(S,i,1),addedge(i+120,T,1);
		outint(n-maxflow());pc('\n');
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值