PowerOj 1736(网络流—最大流)
来源:互联网 发布:淘宝脏辫接发视频教程 编辑:程序博客网 时间:2024/06/16 22:41
第二次世界大战时期,英国皇家空军从沦陷国征募了大量外籍飞行员。由皇家空军派出的每一架飞机都需要配备在航行技能和语言上能互相配合的2名飞行员,其中1名是英国飞行员,另1 名是外籍飞行员。在众多的飞行员中,每一名外籍飞行员都可以与其他若干名英国飞行员很好地配合。如何选择配对飞行的飞行员才能使一次派出最多的飞机。对于给定的外籍飞行员与英国飞行员的配合情况,试设计一个算法找出最佳飞行员配对方案,使皇家空军一次能派出最多的飞机。对于给定的外籍飞行员与英国飞行员的配合情况,编程找出一个最佳飞行员配对方案,使皇家空军一次能派出最多的飞机。
Input
由文件input.txt提供输入数据。文件第1行有2个正整数m和n。n是皇家空军的飞行员总数(n<100);m是外籍飞行员数。外籍飞行员编号为1~m;英国飞行员编号为m+1~n。接下来每行有2个正整数i和j,表示外籍飞行员i可以和英国飞行员j配合。文件最后以2个-1结束。
Output
程序运行结束时,将最佳飞行员配对方案输出到文件output.txt中。第1行是最佳飞行员配对方案一次能派出的最多的飞机数M。接下来M行是最佳飞行员配对方案。每行有2个正整数i和j,表示在最佳飞行员配对方案中,飞行员i和飞行员j配对。如果所求的最佳飞行员配对方案不存在,则输出‘No Solution!’。
Sample Input
5 101 71 82 62 92 103 73 84 74 85 10-1 -1
Sample Output
41 72 93 85 10
EK代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=105;
const int maxm=4004;
const int INF=0x3f3f3f3f;
int head[maxn],pre[maxn],vis[maxn];
int n,m,tot=0;
inline int read()//输入外挂
{
char ls=getchar();for (;ls<'0'||ls>'9';ls=getchar());
int x=0;for (;ls>='0'&&ls<='9';ls=getchar())x=x*10+ls-'0';
return x;
}
struct node
{
int to,next,flow;//记录边,剩余流量
node(){}
node(int to,int next,int flow):to(to),next(next),flow(flow){}
}edge[maxm];
void init()
{
tot=0;
memset(head,-1,sizeof(head));
}
void add(int u,int v,int w)//有负边
{
edge[tot]=node(v,head[u],w);//负边流量为w
head[u]=tot++;
edge[tot]=node(u,head[v],0);//起始点边流量为0
head[v]=tot++;
}
int find_path(int st,int en)//实际上就是bfs搜出可以流的边
{
memset(vis,0,sizeof(vis));
queue<int>q;
q.push(st);
vis[st]=1;//标记是否流过这条边,开始时候先让他流一次
while(!q.empty())
{
int u=q.front();
q.pop();
if(u==en) return 1;//已经找到一条满足条件路径
for(int i=head[u];~i;i=edge[i].next)
{
if(0==edge[i].flow) continue;//剩余流量为0
int v=edge[i].to;
if(!vis[v])
{
vis[v]=1;
q.push(v);
pre[v]=i;//记录前驱的边(正向边)
}
}
}
return 0;
}
int EK(int st,int en)
{
int ans=0;
while(find_path(st,en))
{
int flow=INF;
for(int i=en;i!=st;i=edge[pre[i]^1].to)//倒着求,正向边是pre[i],那么反向边就是pre[i^1],当然要从0开始
{
flow=min(flow,edge[pre[i]].flow);//取剩余流量最小的
}
for(int i=en;i!=st;i=edge[pre[i]^1].to)
{
edge[pre[i]].flow-=flow;//由于倒着跑,所以正向边当然是减去
edge[pre[i]^1].flow+=flow;//反向边当然就是加了
}
ans+=flow;
}
return ans;
}
int main()
{
n=read();
m=read();
init();
for(int i=1;i<=n;i++)add(0,i,1);//初始化流量都为1
for(int i=n+1;i<=m;i++)add(i,m+1,1);//0-i,i-m+1建图
int u,v;
while(~scanf("%d%d",&u,&v))
{
if(u==-1&&v==-1) break;
add(u,v,1);
}
int ans=EK(0,m+1);
if(ans==0)
{
printf("NoSolution!\n");
//break;
return 0;
}
printf("%d\n",ans);
for(int i=1;i<=n;i++)//n比较小,直接暴力找
{
for(int j=head[i];~j;j=edge[j].next)
{
if(edge[j].flow==0&&edge[j].to>n)
{
printf("%d%d\n",i,edge[j].to);
break;
}
}
}
return 0;
}
dinic代码using namespace std;
const int maxn = 100;
const int maxm = 4000;
struct EDGE
{
int to, next, flow;
EDGE(int to = 0, int next = 0, int flow = 0): to(to), next(next), flow(flow) {}
} edge[maxm];
int head[maxn], edgecnt;
void init()
{
memset(head, -1, sizeof(head));
edgecnt = 0;
}
void AddEdge(int s, int t, int c)
{
edge[edgecnt] = EDGE(t, head[s], c);
head[s] = edgecnt++;
edge[edgecnt] = EDGE(s, head[t], 0);
head[t] = edgecnt++;
}
int layer[maxn];
int p[maxn];
bool GetLayer(int st, int en)
{
memset(layer, 0, sizeof(int) * (en + 1));
layer[st] = 1;
queue<int>q;
q.push(st);
while(!q.empty())
{
int u = q.front();
q.pop();
for(int i = head[u]; ~i; i = edge[i].next)
{
if(edge[i].flow == 0) continue;
int v = edge[i].to;
if(layer[v]) continue;
layer[v] = layer[u] + 1;
q.push(v);
}
}
return layer[en];
}
int dfsFlow(int u, int en, int f)
{
int ret = 0;
if(u == en) return f;
if(layer[u] >= layer[en]) return 0;
for(; ~p[u]; p[u] = edge[p[u]].next)
{
if(edge[p[u]].flow == 0) continue;
int v = edge[p[u]].to;
if(layer[v] != layer[u] + 1) continue;
int temp = dfsFlow(v, en, min(f, edge[p[u]].flow));
ret += temp;
f -= temp;
edge[p[u]].flow -= temp;
edge[p[u] ^ 1].flow += temp;
if(f == 0) break;
}
return ret;
}
int dinic(int st, int en)
{
int ans = 0;
while(GetLayer(st, en))
{
memcpy(p, head, sizeof(int) * (en + 1));
ans += dfsFlow(st, en, INT_MAX);
}
return ans;
}
int main()
{
init();
int n, m;
scanf("%d %d", &n, &m);
for(int i = 1; i <= n; i++)
AddEdge(0, i, 1);
for(int i = n + 1; i <= m; i++)
AddEdge(i, m + 1, 1);
int u, v;
while(scanf("%d %d", &u, &v), u != -1 && v != -1)
{
AddEdge(u, v, 1);
}
int ans = dinic(0, m + 1);
if(ans == 0)
{
printf("No Solution!");
return 0;
}
printf("%d\n", ans);
for(int i = 1; i <= n; i++)
for(int j = head[i]; ~j; j = edge[j].next)
if(edge[j].to > n && edge[j].flow == 0)
{
printf("%d %d\n", i, edge[j].to);
break;
}
return 0;
}
- PowerOj 1736(网络流—最大流)
- PowerOJ 1679: Drainage Ditches(网络流入门) 最大流模板
- PowerOJ 1737 网络流24题之二 太空飞行计划问题(最大权闭合子图)
- 网络流—最大流
- 网络最大流(SAP)
- 最大网络流(Dinic)
- 网络流--最大流
- 最大流(网络流)
- 网络流 最大流
- 网络流最大流
- 网络流 最大流
- 网络流-最大流
- 网络流--最大流
- 网络流-最大流
- 网络流 最大流
- 网络流-最大流
- 网络流,最大流
- 最大网络流
- PHP设计模式系列(十六):单例模式
- RSA加解密
- 性能测试中WAS常用修改
- 程序包javax.servlet不存在
- C语言 scanf在while循环里的无限循环
- PowerOj 1736(网络流—最大流)
- 【BFS】(一)抓住那头牛(poj 3278)
- Java IO流之【缓冲流和文件流复制文件对比】
- 湖南省第八届省赛,最小生成树Prim算法+利用二进制的状态枚举
- JVM学习笔记(八)类加载机制-类加载器
- 博客地址
- 囧字构造 模拟
- JVM源码分析之FinalReference完全解读
- 多线程之 synchronized 和 volatile