您的位置:首页 > 理论基础 > 计算机网络

[kuangbin带你飞]专题十一 网络流

2016-04-06 19:05 525 查看
ID
Origin
Title
34 / 81Problem APOJ 3436ACM Computer Factory
92 / 195Problem BPOJ 3281Dining
55 / 148Problem CPOJ 1087A Plug for UNIX
59 / 111Problem DPOJ 2195Going Home
44 / 132Problem EPOJ 2516Minimum Cost
35 / 72Problem FPOJ 1459Power Network
40 / 217Problem GHDU 4280Island Transport
42 / 133Problem HHDU 4292Food
34 / 90Problem IHDU 4289Control
28 / 90Problem JUVA 10480Sabotage
19 / 37Problem KHDU 2732Leapin' Lizards
13 / 136Problem LHDU 3338Kakuro Extension
36 / 358Problem MHDU 3605Escape
17 / 58Problem NHDU 3081Marriage Match II
15 / 61Problem OHDU 3416Marriage Match IV
34 / 81 Problem A POJ 3436 ACM Computer Factory

没懂。。

此题是最大流问题。题目意思比较难懂。
看得比较纠结。
就是说有N台组装电脑的机器。电脑的组成部分共有P部分。
每台机器有P个输入输出规格。还有一个容量Q;

其中输入规格有三种情况:0,1,2

0:该部分不能存在

1:该部分必须保留

2:该部分可有可无

输出规格有2种情况:0,1

0:该部分不存在

1:该部分存在

要求的是生产电脑最大的台数,就是求网络中的最大流。

这相当于是生产线。需要自己去建图。

但是考虑到每台机器都有容量,所以把一台机器分成两个点,中间建一条容量的边。

同时如果一台机器的输出符合另一台机器的输入,则建一条容量无穷大的边。

同时要增加源点和汇点。输入没有1的连接源点,输出全部是1的连接汇点。

92 / 195 Problem B POJ 3281 Dining

本题能够想到用最大流做,那真的是太绝了。建模的方法很妙!
题意就是有N头牛,F个食物,D个饮料。
N头牛每头牛有一定的喜好,只喜欢几个食物和饮料。
每个食物和饮料只能给一头牛。一头牛只能得到一个食物和饮料。
而且一头牛必须同时获得一个食物和一个饮料才能满足。问至多有多少头牛可以获得满足。
最初相当的是二分匹配。但是明显不行,因为要分配两个东西,两个东西还要同时满足。
最大流建图是把食物和饮料放在两端。一头牛拆分成两个点,两点之间的容量为1.喜欢的食物和饮料跟牛建条边,容量为1.
加个源点和汇点。源点与食物、饮料和汇点的边容量都是1,表示每种食物和饮料只有一个。
这样话完全是最大流问题了,。

//1002
/*
HDU 4289
G++  62ms  1888K
最大流
SAP
*/
#include<stdio.h>
#include<iostream>
#include<map>
#include<set>
#include<algorithm>
#include<string.h>
#include<stdlib.h>
using namespace std;

const int MAXN=5000;//点数的最大值
const int MAXM=2500000;//边数的最大值
const int INF=0x3f3f3f3f;

struct Node
{
int from,to,next;
int cap;
}edge[MAXM];
int tol;
int head[MAXN];
int dep[MAXN];
int gap[MAXN];//gap[x]=y:说明残留网络中 dep[i]==x的个数为y

int n;//点的实际个数,一定是总的点的个数,包括源点和汇点
void init()
{
tol=0;
memset(head,-1,sizeof(head));
}
void addedge(int u,int v,int w)
{
edge[tol].from=u;
edge[tol].to=v;
edge[tol].cap=w;
edge[tol].next=head[u];
head[u]=tol++;
edge[tol].from=v;
edge[tol].to=u;
edge[tol].cap=0;
edge[tol].next=head[v];
head[v]=tol++;
}
void BFS(int start,int end)
{
memset(dep,-1,sizeof(dep));
memset(gap,0,sizeof(gap));
gap[0]=1;
int que[MAXN];
int front,rear;
front=rear=0;
dep[end]=0;
que[rear++]=end;
while(front!=rear)
{
int u=que[front++];
if(front==MAXN)front=0;
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].to;
if(edge[i].cap!=0||dep[v]!=-1)continue;
que[rear++]=v;
if(rear==MAXN)rear=0;
dep[v]=dep[u]+1;
++gap[dep[v]];
}
}
}
int SAP(int start,int end)
{
int res=0;
BFS(start,end);
int cur[MAXN];
int S[MAXN];
int top=0;
memcpy(cur,head,sizeof(head));
int u=start;
int i;
while(dep[start]<n)
{
if(u==end)
{
int temp=INF;
int inser;
for(i=0;i<top;i++)
if(temp>edge[S[i]].cap)
{
temp=edge[S[i]].cap;
inser=i;
}
for(i=0;i<top;i++)
{
edge[S[i]].cap-=temp;
edge[S[i]^1].cap+=temp;
}
res+=temp;
top=inser;
u=edge[S[top]].from;
}
if(u!=end&&gap[dep[u]-1]==0)//出现断层,无增广路
break;
for(i=cur[u];i!=-1;i=edge[i].next)
if(edge[i].cap!=0&&dep[u]==dep[edge[i].to]+1)
break;
if(i!=-1)
{
cur[u]=i;
S[top++]=i;
u=edge[i].to;
}
else
{
int min=n;
for(i=head[u];i!=-1;i=edge[i].next)
{
if(edge[i].cap==0)continue;
if(min>dep[edge[i].to])
{
min=dep[edge[i].to];
cur[u]=i;
}
}
--gap[dep[u]];
dep[u]=min+1;
++gap[dep[u]];
if(u!=start)
u=edge[S[--top]].from;
}

}
return res;
}

int main()
{
//freopen("B.in","r",stdin);
//freopen("B.out","w",stdout);
int N,M;
int u,v;
int start;
int end;
while(scanf("%d%d",&N,&M)!=EOF)
{
init();
scanf("%d%d",&start,&end);
start=2*start-1;
end=2*end;
n=2*N;
for(int i=1;i<=N;i++)
{
scanf("%d",&u);
addedge(2*i-1,2*i,u);
addedge(2*i,2*i-1,u);
}
while(M--)
{
scanf("%d%d",&u,&v);
addedge(2*u,2*v-1,INF);
addedge(2*v,2*u-1,INF);//这里一定要注意
}
printf("%d\n",SAP(start,end));
}
return 0;
}


View Code

28 / 90 Problem J UVA 10480 Sabotage

最大流

19 / 37 Problem K HDU 2732 Leapin' Lizards

最大流

13 / 136 Problem L HDU 3338 Kakuro Extension

很神奇的最大流的题目。很有意思。

题目意思就是在n*m的格子中,有黑白两种格子。要在白格子中填入数字1~9
* 每一段横竖连续的白格子的和是知道的。
* 求出一种满足的,保证有解。
* 最大流。
* 按照横竖段进行编号。然后行进列出,构造图形。
*
* 为了保证填入的数字是1~9,所以一开始每个格子减掉了1,相应的流入和流出都减掉。
* 然后格子的边的赋值为8.
* 还有就是要记录下相应边的编号,便于输出结果。

36 / 358 Problem M HDU 3605 Escape

这题一看题目是很简单的最大流。
但是数据好大,试了很多模板,都是TLE。
后来发现可以合并点,
因为m<=10.
所以用二进制记录。
在n个点中,如果是一样的就合并。
这样最多是1024+m+2个点。

但是这题还是很坑。。。。在HDU上用G++交无论如何都是TLE的。直接读入数据输出都是TLE.
改成C++就AC了。。。

17 / 58 Problem N HDU 3081 Marriage Match II

最大流+二分+并查集

15 / 61 Problem O HDU 3416 Marriage Match IV

这题就是求从A到B的最短路径的条数。

一条边只能经过一次。

先通过最短路去除掉没有用的边。

然后用一次最大流就是答案了。

从A和B分别出发求最短路dist1,dist2.

注意从B求得额时候要反向。

如果dist1[a]+dist2[b]+c==dist1[B].那么这条边就是有用的。。

我用的SPFA求最短路的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: