网络流24题题解(待更)

好像题目大多数都很容易

1.飞行员配对方案问题
题意 给你n个主飞行员,m个副飞行员,他们之间可以相互匹配,问最多可以匹配几对
一句话:主飞行员连源点,副飞行员连汇点,然后连边后跑最大流

#include<bits/stdc++.h>
using namespace std;

int m,n,tot=-1,h[1005],ans=0,tp=0;

struct node{
	int from,next,to,rest;
	int last;
}e[10005];

void add(int x,int y,int z){
	tot++;
	e[tot].next=h[x];
	h[x]=tot;
	e[tot].from=x;
	e[tot].to=y;
	e[tot].rest=z;
}

int dis[1005],g[1005],flow[1005];
bool vis[1005];

int bfs(int s,int t){
	queue<int>q;
	dis[s]=0;
	q.push(s);vis[s]=true;
	while(!q.empty()){
		int u=q.front();vis[u]=false;q.pop();
		for(int i=h[u];i!=(-1);i=e[i].next){
			if(dis[e[i].to]>dis[u]+1&&g[e[i].to]==(-1)&&e[i].rest>0){
				g[e[i].to]=i;
				flow[e[i].to]=min(flow[u],e[i].rest);
				dis[e[i].to]=dis[u]+1;
				if(vis[e[i].to]==false){
					vis[e[i].to]=true;
					q.push(e[i].to);
				}
			}
		}
	}
}

int EK(int s,int t){
	while(1){
		memset(dis,0x7f,sizeof(dis));
		memset(vis,false,sizeof(vis));
		memset(flow,0x7f,sizeof(flow));
		memset(g,-1,sizeof(g));
		bfs(s,t);
		if(g[t]==(-1))return 0;
		ans+=flow[t];
		for(int p=t;p!=(s);p=e[g[p]].from){
			e[g[p]].rest-=flow[t];
			e[g[p]].last=tp;
			e[g[p]^1].rest+=flow[t];
		}
	}
}

int main(){
	memset(h,-1,sizeof(h));
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		add(0,i,1);
		add(i,0,0);
	}
	for(int i=m+1;i<=n;i++){
		add(i,n+1,1);
		add(n+1,i,0);
	}int x,y;
	while(scanf("%d%d",&x,&y)!=EOF){
		add(x,y,1);
		add(y,x,0);
	}
	EK(0,n+1);
	if(ans==0){
		cout<<"No Solution!"<<endl;
		exit(0);
	}
	cout<<ans<<endl;
	
}

2.太空飞行计划
题意 裸的最大权闭合子图,
一句话 :直接套网络流 想看蒟蒻的垃圾证明的移步最大权闭合子图 瞎证明

#include<bits/stdc++.h>
using namespace std;

int m,n,tot=-1,h[10005],ans=0,bianhao[505][505],co[505],sum=0;
bool wll[10005];
struct node{
	int from,next,to,rest;
	int last;
}e[100005];

void add(int x,int y,int z){
	tot++;
	e[tot].next=h[x];
	h[x]=tot;
	e[tot].from=x;
	e[tot].to=y;
	e[tot].rest=z;
}

int dis[10005],g[10005],flow[10005];
bool vis[10005];

int bfs(int s,int t){
	queue<int>q;
	dis[s]=0;
	q.push(s);vis[s]=true;
	while(!q.empty()){
		int u=q.front();vis[u]=false;q.pop();
		for(int i=h[u];i!=(-1);i=e[i].next){
			if(dis[e[i].to]>dis[u]+1&&g[e[i].to]==(-1)&&e[i].rest>0){
				g[e[i].to]=i;
				flow[e[i].to]=min(flow[u],e[i].rest);
				dis[e[i].to]=dis[u]+1;
				if(vis[e[i].to]==false){
					vis[e[i].to]=true;
					q.push(e[i].to);
				}
			}
		}
	}
}

int EK(int s,int t){
	while(1){
		bfs(s,t);
		if(g[t]==(-1))return 0;
		ans+=flow[t];
		for(int p=t;p!=(s);p=e[g[p]].from){
			e[g[p]].rest-=flow[t];
			e[g[p]^1].rest+=flow[t];
		}	
		memset(dis,0x7f,sizeof(dis));
		memset(vis,false,sizeof(vis));
		memset(flow,0x7f,sizeof(flow));
		memset(g,-1,sizeof(g));
	}
}

int main(){
	//freopen("shut1.in","r",stdin);
	memset(dis,0x7f,sizeof(dis));
	memset(vis,false,sizeof(vis));
	memset(flow,0x7f,sizeof(flow));
	memset(g,-1,sizeof(g)); 
	memset(h,(-1),sizeof(h));
	memset(bianhao,0,sizeof(bianhao));
	cin>>m>>n;
	for(int i=1;i<=m;i++){
		int mo,k;cin>>mo;sum+=mo;
		add(0,i,mo);
		add(i,0,0);
		char a;
		while(1){
			a=getchar();if(a=='\n'||a=='\r'||a==EOF)break;
			bianhao[i][0]++;
			cin>>bianhao[i][bianhao[i][0]];
		}
	}
	for(int i=1;i<=n;i++){
		cin>>co[i];
		add(m+i,m+n+1,co[i]);
		add(m+n+1,m+i,0);
	}
	for(int i=1;i<=m;i++){
		for(int j=1;j<=bianhao[i][0];j++){
			add(i,m+bianhao[i][j],9999999);
			add(m+bianhao[i][j],i,0);
		}
	}
	EK(0,m+n+1);
	int jk;
	for(int i=h[0];i!=(-1);i=e[i].next){
		if(dis[e[i].to]<99999){
			cout<<e[i].to;
			for(int j=1;j<=bianhao[e[i].to][0];j++)wll[bianhao[e[i].to][j]]=true;
			jk=e[i].next;
			break;
		}
	}
	for(int i=jk;i!=(-1);i=e[i].next){
		if(dis[e[i].to]<99999){
			for(int j=1;j<=bianhao[e[i].to][0];j++)wll[bianhao[e[i].to][j]]=true;
			cout<<" "<<e[i].to;
		}
	}
	cout<<endl;
	for(int i=1;i<=n;i++){
		if(wll[i]==true){
			cout<<i;
			jk=i+1;
			break;
		}
	}
	for(int i=jk;i<=n;i++){
		if(wll[i]==true){
			cout<<" "<<i;
		}
	}
	cout<<endl;
	cout<<sum-ans<<endl;
} 

3.最小路径覆盖
题意 给你一个有向图,问你最少几条路径可以覆盖他
题解:
这个问题转换为网络流问题很值得思考啊
首先考虑建图,我们先将原图的每一个点拆分成两个
然后对于第一个,每一个链接源点,第二个每一个链接汇点
然后中间有边链接的,就把起点的第一个连上终点的第1个
然后对于那些没有出度的点(可以作为终点),就把他第一个点第二个点连上
然后跑一下最小割(把原图分为两段)
然后最大流就行了
4.魔术球
题意:给你n个柱子,问你可以在上面放多少个编号连续且每根柱子上相邻的编号为平方数的球
洗澡时候想的,根据平方数这个关系建边,然后枚举多少个柱子,然后再在图上跑最小路径覆盖,若路径条数大于柱子数,那么珠子数-1就是答案
5.圆桌聚餐
题意:给你m个国家,每个国家代表数为ri,n个餐桌,每个餐桌上的代表都是不同国家的,且容量为Ci,问最多情况下且满足题意的方案,并输出方案
题解:很水吧…首先源点连每一个国家,且建边,且容量代表数,而后把每一个餐桌和每一个国家建边,边容量为1,然后每个餐桌后面跟着一个点,容量为ci,然后再连向汇点,然后在上面跑最大流就ok了有紫题??
6.最长递增子序列
啊!!!没注意第一小题给出的解题条件,我还在想,怎么保证建图(递增序列长k)Fi1的可能是起点,Fik的一定是终点
题意,三个小题,自己看把…
第一小题送的
第二小题直接建好图跑最大流
第三小题 直接改一下限制,然后跑最大流
7.

讲道理都做的差不多了…

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值