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

网络流

2015-11-16 16:03 716 查看
上连接:

初期,比较简单
http://www.cnblogs.com/exponent/archive/2011/11/11/2245324.html
poj 1459

网络流模板题

模板来自kuangbin

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<queue>
using namespace std;
const int MAXN=110;
const int INF=0x7fffffff;
int map[MAXN][MAXN],path[MAXN],flow[MAXN],start,end;
int n;//点的个数
queue<int>q;
int bfs()
{
int i,t;
while(!q.empty()) q.pop();//清空队列
memset(path,-1,sizeof(path));
path[start]=0;
flow[start]=INF;
q.push(start);
while(!q.empty())
{
t=q.front();
q.pop();
if(t==end)  break;
for(i=0;i<=n;i++)
{
if(i!=start&&path[i]==-1&&map[t][i])
{
flow[i]=flow[t]<map[t][i]?flow[t]:map[t][i];
q.push(i);
path[i]=t;
}
}

}
if(path[end]==-1)  return -1;
return flow
;
}
int Edmonds_Karp()
{
int max_flow=0,step,now,pre;
while((step=bfs())!=-1)
{
max_flow+=step;
now=end;
while(now!=start)
{
pre=path[now];
map[pre][now]-=step;
map[now][pre]+=step;
now=pre;
}
}
return max_flow;
}
int main()
{
int i,u,v,z,np,nc,m;
while(scanf("%d%d%d%d",&n,&np,&nc,&m)!=EOF)
{
memset(map,0,sizeof(map));
while(m--)
{
while(getchar()!='(');
scanf("%d,%d)%d",&u,&v,&z);
u++;v++;
map[u][v]=z;
}
while(np--)
{
while(getchar()!='(');
scanf("%d)%d",&u,&z);
u++;
map[0][u]=z;
}
while(nc--)
{
while(getchar()!='(');
scanf("%d)%d",&u,&z);
u++;
map[u][n+1]=z;
}
n++;
start=0;end=n;
printf("%d\n",Edmonds_Karp());
}
return 0;
}


poj 1698

这个是建图

题意:有N部电影,分别可以在一个星期的几天拍摄,并可以拍W个星期,Alice可以有D个星期拍这部电影,一天只能拍一部电影。问Alice能否拍完所有电影。

让0作为源点,377(377不会再星期+日期中出现的)作为汇点

首先0-n之间的每一个都要连一条容量为D的边(n为每个电影上)

接着从n-(i*7+j)//第i星期第j天之间连一条容量为1的边

最后从每星期的每一天到汇点377都连一条容量为1的边

sum+=D;

跑一遍DINIC,判断sum与最大流量是否相等即可。

#include <map>
#include <set>
#include <stack>
#include <queue>
#include <cmath>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <sstream>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#pragma comment(linker,"/STACK:102400000,102400000")

using namespace std;
#define   MAX           100005
#define   MAXN          10000005
#define   maxnode       500005
#define   sigma_size    30
#define   lson          l,m,rt<<1
#define   rson          m+1,r,rt<<1|1
#define   lrt           rt<<1
#define   rrt           rt<<1|1
#define   middle        int m=(r+l)>>1
#define   LL            long long
#define   ull           unsigned long long
#define   mem(x,v)      memset(x,v,sizeof(x))
#define   lowbit(x)     (x&-x)
#define   pii           pair<int,int>
#define   bits(a)       __builtin_popcount(a)
#define   mk            make_pair

const int    prime = 999983;
const int    INF   = 0x3f3f3f3f;
const LL     INFF  = 1e18;
const double pi    = 3.141592653589793;
const double inf   = 1e18;
const double eps   = 1e-8;
const int    mod   = 100007;
const ull    mx    = 133333331;

/*****************************************************/
inline void RI(int &x) {
char c;
while((c=getchar())<'0' || c>'9');
x=c-'0';
while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0';
}
/*****************************************************/

int N, NP, NC, M;
struct Edge
{
int u, v, cap;
Edge() {}
Edge(int u, int v, int cap): u(u), v(v), cap(cap) {}
} es[350 * 350];
int R, S, T;
vector<int> tab[350+40]; // 边集
int dis[350+40];
int current[350+40];
void addedge(int u, int v, int cap)
{
tab[u].push_back(R);
es[R++] = Edge(u, v, cap); // 正向边
tab[v].push_back(R);
es[R++] = Edge(v, u, 0); // 反向边容量为0
// 正向边下标通过异或就得到反向边下标, 2 ^ 1 == 3 ; 3 ^ 1 == 2
}
int BFS()
{
queue<int> q;
q.push(S);
memset(dis, 0x3f, sizeof(dis));
dis[S] = 0;
while (!q.empty())
{
int h = q.front();
q.pop();
for (int i = 0; i < tab[h].size(); i++)
{
Edge &e = es[tab[h][i]];
if (e.cap > 0 && dis[e.v] == 0x3f3f3f3f)
{
dis[e.v] = dis[h] + 1;
q.push(e.v);
}
}
}
return dis[T] < 0x3f3f3f3f; // 返回是否能够到达汇点
}
int dinic(int x, int maxflow)
{
if (x == T)
return maxflow;
// i = current[x] 当前弧优化
for (int i = current[x]; i < tab[x].size(); i++)
{
current[x] = i;
Edge &e = es[tab[x][i]];
if (dis[e.v] == dis[x] + 1 && e.cap > 0)
{
int flow = dinic(e.v, min(maxflow, e.cap));
if (flow)
{
e.cap -= flow; // 正向边流量降低
es[tab[x][i] ^ 1].cap += flow; // 反向边流量增加
return flow;
}
}
}
return 0; // 找不到增广路 退出
}
int DINIC()
{
int ans = 0;

while (BFS()) // 建立分层图
{
int flow;
memset(current, 0, sizeof(current)); // BFS后应当清空当前弧数组
while (flow = dinic(S, 0x3f3f3f3f)) // 一次BFS可以进行多次增广
ans += flow;
}
return ans;
}
int f[60][10];
void ori(){
R=0;
memset(f,0,sizeof(f));
for(int i=0;i<350+40;i++)
tab[i].clear();

}

int main(){
int t,n,W,D,sum,flag;
scanf("%d",&t);
while(t--){
ori();
sum=0;
flag=0;
scanf("%d",&n);
for(int i=1;i<=n;i++){
for(int j=1;j<=7;j++)scanf("%d",&f[i][j]);
scanf("%d%d",&D,&W);
sum+=D;
if(W>flag)flag=W;
addedge(0,i,D);
for(int p=1;p<=W;p++)for(int q=1;q<=7;q++)if(f[i][q])addedge(i,7*p+q+n,1);

}
S=0;
for(int i=1;i<=flag;i++)for(int j=1;j<=7;j++)addedge(7*i+j+n,377,1);
T=377;
int re=DINIC();
if(sum==re)printf("Yes\n");
else printf("No\n");

}

}


poj 2112

额,这个题真是做的人心好累

题意:有K台挤奶机(编号1~K),C头奶牛(编号K+1~K+C),给出各点之间距离。现在要让C头奶牛到挤奶机去挤奶,每台挤奶机只能处理M头奶牛,求使所走路程最远的奶牛的路程最短的方案。

构图:先Floyd求所有点对之间最短路,二分最短长度,若奶牛与挤奶机之间的距离大于mid则不连边,否则连容量为1的边。源向挤奶机连容量M的边,奶牛向汇连容量1的边,用最大流判可行性。

问了问逊哥,说求最长路径的最短值,典型的二分特政......

然后在写的过程中也是各种错,我觉得都是些可以避免的错......像把K和C的含义搞反,像少写了<号,还是素养的问题,你自己多反思......

然后近段时间有进步吧,不过写题还是很慢,算了只能慢慢写了,上代码,代码比较不是很好看,用的是DINIC,速度还行......

#include <map>
#include <set>
#include <stack>
#include <queue>
#include <cmath>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <sstream>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#pragma comment(linker,"/STACK:102400000,102400000")

using namespace std;
#define   MAX           100005
#define   MAXN          10000005
#define   maxnode       500005
#define   sigma_size    30
#define   lson          l,m,rt<<1
#define   rson          m+1,r,rt<<1|1
#define   lrt           rt<<1
#define   rrt           rt<<1|1
#define   middle        int m=(r+l)>>1
#define   LL            long long
#define   ull           unsigned long long
#define   mem(x,v)      memset(x,v,sizeof(x))
#define   lowbit(x)     (x&-x)
#define   pii           pair<int,int>
#define   bits(a)       __builtin_popcount(a)
#define   mk            make_pair

const int    prime = 999983;
const int    INF   = 0x3f3f3f3f;
const LL     INFF  = 1e18;
const double pi    = 3.141592653589793;
const double inf   = 1e18;
const double eps   = 1e-8;
const int    mod   = 100007;
const ull    mx    = 133333331;

/*****************************************************/
inline void RI(int &x) {
char c;
while((c=getchar())<'0' || c>'9');
x=c-'0';
while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0';
}
/*****************************************************/

int N, NP, NC, M;
int len[230*230+10];
struct Edge
{
int u, v, cap;
Edge() {}
Edge(int u, int v, int cap): u(u), v(v), cap(cap) {}
} es[400*400];
int R, S, T;
vector<int> tab[350+40]; // 边集
int dis[350+40];
int current[350+40];
void addedge(int u, int v, int cap)
{
tab[u].push_back(R);
es[R++] = Edge(u, v, cap); // 正向边
tab[v].push_back(R);
es[R++] = Edge(v, u, 0); // 反向边容量为0
// 正向边下标通过异或就得到反向边下标, 2 ^ 1 == 3 ; 3 ^ 1 == 2
}
int BFS()
{
queue<int> q;
q.push(S);
memset(dis, 0x3f, sizeof(dis));
dis[S] = 0;
while (!q.empty())
{
int h = q.front();
q.pop();
for (int i = 0; i < tab[h].size(); i++)
{
Edge &e = es[tab[h][i]];
if (e.cap > 0 && dis[e.v] == 0x3f3f3f3f)
{
dis[e.v] = dis[h] + 1;
q.push(e.v);
}
}
}
return dis[T] < 0x3f3f3f3f; // 返回是否能够到达汇点
}
int dinic(int x, int maxflow)
{
if (x == T)
return maxflow;
// i = current[x] 当前弧优化
for (int i = current[x]; i < tab[x].size(); i++)
{
current[x] = i;
Edge &e = es[tab[x][i]];
if (dis[e.v] == dis[x] + 1 && e.cap > 0)
{
int flow = dinic(e.v, min(maxflow, e.cap));
if (flow)
{
e.cap -= flow; // 正向边流量降低
es[tab[x][i] ^ 1].cap += flow; // 反向边流量增加
return flow;
}
}
}
return 0; // 找不到增广路 退出
}
int DINIC()
{
int ans = 0;

while (BFS()) // 建立分层图
{
int flow;
memset(current, 0, sizeof(current)); // BFS后应当清空当前弧数组
while (flow = dinic(S, 0x3f3f3f3f)) // 一次BFS可以进行多次增广
ans += flow;
}
return ans;
}
//int f[60][10];
int Map[300][300];
int cnt;
void ori(){
//memset(Map,INF,sizeof(Map));
R=0;
for(int i=0;i<350+40;i++)
tab[i].clear();

}
int k,c,m;
void floyd()
{
int i,j,q;
for( q=1;q<=k+c;++q )
for( i=1;i<=k+c;++i )
for( j=1;j<=k+c;++j )
Map[i][j]=min(Map[i][j],Map[i][q]+Map[q][j]);
}
bool cmp(int a,int b){
return a<b;
}
bool judge(int M){//c cow k machine
ori();
R=0;
for(int i=0;i<350+40;i++)tab[i].clear();
for(int i=1;i<=k;i++)addedge(0,i,m);
for(int i=k+1;i<=k+c;i++)for(int j=1;j<=k;j++)if(Map[i][j]<=M)addedge(j,i,1);//from machine to cow
for(int i=k+1;i<=k+c;i++)addedge(i,377,1);//from cow to T
S=0;T=377;
int re=DINIC();
if(re<c)return false;
return true;

}
int main(){

while(~scanf("%d%d%d",&k,&c,&m)){
cnt=0;
memset(Map,INF,sizeof(INF));
for(int i=1;i<=k+c;i++)for(int j=1;j<=k+c;j++){
scanf("%d",&Map[i][j]);
if(i!=j&&Map[i][j]==0)Map[i][j]=INF;
Map[j][i]=Map[i][j];
}

floyd();
for(int i=1;i<=k+c;i++)for(int j=1;j<=k+c;j++){if(i==j)continue;len[cnt++]=Map[i][j];}
sort(len,len+cnt,cmp);
int L=0,R=cnt-1;
while(L<=R){
int Mid=(L+R)/2;
int X=len[Mid];
if(judge(X))R=Mid-1;
else L=Mid+1;
}
printf("%d\n",len[L]);
}

}


poj 2455

题意:有N个农场,P条无向路连接。要从1到N不重复走T条路,求所经过的直接连接两个区域的道路中最长道路中的最小值.

构图:源点向1连容量T的边。二分最小长度,(最长道路的最小值)长度超过mid的边容量为0,否则为1,用最大流判可行性。

注意:1.该题有重边,切忌用邻接矩阵删除重边(重边要用邻接表来处理以保留)。

2.无向图在addedge中要进行处理(处理方式见代码)。

在addedge()中,有一部分要改一下

void addedge(int u, int v, int cap)

{

tab[u].push_back(R);

es[R++] = Edge(u, v, cap); // 正向边

tab[v].push_back(R);

es[R++] = Edge(v, u, 0); // 反向边容量为0

// 正向边下标通过异或就得到反向边下标, 2 ^ 1 == 3 ; 3 ^ 1 == 2

}

改为:
void addedge(int u, int v, int cap)

{

tab[u].push_back(R);

es[R++] = Edge(u, v, cap); // 正向边

tab[v].push_back(R);

es[R++] = Edge(v, u, cap); // 反向边容量为cap 对无向图来说

// 正向边下标通过异或就得到反向边下标, 2 ^ 1 == 3 ; 3 ^ 1 == 2

}

刚开始就是这个地方没改,一直WA(最开始是RE,就数组一直在扩......)

以后要随机应变

上代码

#include <map>
#include <set>
#include <stack>
#include <queue>
#include <cmath>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <sstream>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#pragma comment(linker,"/STACK:102400000,102400000")

using namespace std;
#define   MAX           100005
#define   MAXN          10000005
#define   maxnode       500005
#define   sigma_size    30
#define   lson          l,m,rt<<1
#define   rson          m+1,r,rt<<1|1
#define   lrt           rt<<1
#define   rrt           rt<<1|1
#define   middle        int m=(r+l)>>1
#define   LL            long long
#define   ull           unsigned long long
#define   mem(x,v)      memset(x,v,sizeof(x))
#define   lowbit(x)     (x&-x)
#define   pii           pair<int,int>
#define   bits(a)       __builtin_popcount(a)
#define   mk            make_pair

const int    prime = 999983;
const int    INF   = 0x3f3f3f3f;
const LL     INFF  = 1e18;
const double pi    = 3.141592653589793;
const double inf   = 1e18;
const double eps   = 1e-8;
const int    mod   = 100007;
const ull    mx    = 133333331;

/*****************************************************/
inline void RI(int &x) {
char c;
while((c=getchar())<'0' || c>'9');
x=c-'0';
while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0';
}
/*****************************************************/

typedef struct EdgeTmp{
int f,t,cap;
}EdgeTmp;
EdgeTmp Map[80100];
struct Edge
{
int u, v, cap;
Edge() {}
Edge(int u, int v, int cap): u(u), v(v), cap(cap) {}
} es[80100];
int R, S, T;
vector<int> tab[80100]; // 边集
int dis[80100];
int current[80100];
void addedge(int u, int v, int cap)
{
tab[u].push_back(R);
es[R++] = Edge(u, v, cap); // 正向边
tab[v].push_back(R);
es[R++] = Edge(v, u, cap); // 反向边容量为cap
// 正向边下标通过异或就得到反向边下标, 2 ^ 1 == 3 ; 3 ^ 1 == 2
}
int BFS()
{
queue<int> q;
q.push(S);
memset(dis, 0x3f, sizeof(dis));
dis[S] = 0;
while (!q.empty())
{
int h = q.front();
q.pop();
for (int i = 0; i < tab[h].size(); i++)
{
Edge &e = es[tab[h][i]];
if (e.cap > 0 && dis[e.v] == 0x3f3f3f3f)
{
dis[e.v] = dis[h] + 1;
q.push(e.v);
}
}
}
return dis[T] < 0x3f3f3f3f; // 返回是否能够到达汇点
}
int dinic(int x, int maxflow)
{
if (x == T)
return maxflow;
// i = current[x] 当前弧优化
for (int i = current[x]; i < tab[x].size(); i++)
{
current[x] = i;
Edge &e = es[tab[x][i]];
if (dis[e.v] == dis[x] + 1 && e.cap > 0)
{
int flow = dinic(e.v, min(maxflow, e.cap));
if (flow)
{
e.cap -= flow; // 正向边流量降低
es[tab[x][i] ^ 1].cap += flow; // 反向边流量增加
return flow;
}
}
}
return 0; // 找不到增广路 退出
}
int DINIC()
{
int ans = 0;

while (BFS()) // 建立分层图
{
int flow;
memset(current, 0, sizeof(current)); // BFS后应当清空当前弧数组
while (flow = dinic(S, 0x3f3f3f3f)) // 一次BFS可以进行多次增广
ans += flow;
}
return ans;
}

void ori(){

R=0;
for(int i=0;i<80100;i++)
tab[i].clear();

}

int cnt;
int n,k,Tt;
bool judge(int M){
ori();
S=0;
T=n;
addedge(0,1,Tt);
for(int i=0;i<cnt;i++)if(Map[i].cap<=M)addedge(Map[i].f,Map[i].t,1);

int re=DINIC();
if(re<Tt)return false;
return true;

}
int main(){

while(~scanf("%d%d%d",&n,&k,&Tt)){

int L=INF,R=0;
cnt=0;
for(int i=1;i<=k;i++){
int a,b,l;
scanf("%d%d%d",&a,&b,&l);
EdgeTmp tmp;
tmp.f=a,tmp.t=b,tmp.cap=l;
Map[cnt++]=tmp;
if(l<L)L=l;
if(l>R)R=l;
}
while(L<=R){
int Mid=(L+R)/2;
if(judge(Mid))R=Mid-1;
else L=Mid+1;
}
printf("%d\n",L);

}

}


poj 1149

题意和题解我已经无心去写了......

然后这个题一直在RE,然后我就把边表使劲开大,使劲开大,然后他妈的的MLE,然后我就不知道怎么办了,总想着是不是我思路错了,就一直纠结纠结......

后来果断问马神,然后他做了一发,然后他和我说是我数组开小了,我还说不可能(因为边表确实开到了最大)

然后他一来,帮我把customer相关量开到了1500,然后就他妈的AC了

我去,题目明明说的是customer不会过100,不会过100,去他妹的题目,真坑人

上代码

#include <map>
#include <set>
#include <stack>
#include <queue>
#include <cmath>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <sstream>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#pragma comment(linker,"/STACK:102400000,102400000")

using namespace std;
#define   MAX           100005
#define   MAXN          10000005
#define   maxnode       500005
#define   sigma_size    30
#define   lson          l,m,rt<<1
#define   rson          m+1,r,rt<<1|1
#define   lrt           rt<<1
#define   rrt           rt<<1|1
#define   middle        int m=(r+l)>>1
#define   LL            long long
#define   ull           unsigned long long
#define   mem(x,v)      memset(x,v,sizeof(x))
#define   lowbit(x)     (x&-x)
#define   pii           pair<int,int>
#define   bits(a)       __builtin_popcount(a)
#define   mk            make_pair

const int    prime = 999983;
const int    INF   = 0x3f3f3f3f;
const LL     INFF  = 1e18;
const double pi    = 3.141592653589793;
const double inf   = 1e18;
const double eps   = 1e-8;
const int    mod   = 100007;
const ull    mx    = 133333331;
const int cs = 100100 ;

/*****************************************************/
inline void RI(int &x) {
char c;
while((c=getchar())<'0' || c>'9');
x=c-'0';
while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0';
}
/*****************************************************/
int M,N;
int pig[1050],numA[1500],numB[1500],last[1500];
struct Edge
{
int u, v, cap;
Edge() {}
Edge(int u, int v, int cap): u(u), v(v), cap(cap) {}
} es[cs];
int R, S, T;
vector<int> tab[cs]; // 边集
int dis[cs];
int current[cs];
void addedge(int u, int v, int cap)
{
tab[u].push_back(R);
es[R++] = Edge(u, v, cap); // 正向边
tab[v].push_back(R);
es[R++] = Edge(v, u, 0); // 反向边容量为0
// 正向边下标通过异或就得到反向边下标, 2 ^ 1 == 3 ; 3 ^ 1 == 2
}
int BFS()
{
queue<int> q;
q.push(S);
memset(dis, 0x3f, sizeof(dis));
dis[S] = 0;
while (!q.empty())
{
int h = q.front();
q.pop();
for (int i = 0; i < tab[h].size(); i++)
{
Edge &e = es[tab[h][i]];
if (e.cap > 0 && dis[e.v] == 0x3f3f3f3f)
{
dis[e.v] = dis[h] + 1;
q.push(e.v);
}
}
}
return dis[T] < 0x3f3f3f3f; // 返回是否能够到达汇点
}
int dinic(int x, int maxflow)
{
if (x == T)
return maxflow;
// i = current[x] 当前弧优化
for (int i = current[x]; i < tab[x].size(); i++)
{
current[x] = i;
Edge &e = es[tab[x][i]];
if (dis[e.v] == dis[x] + 1 && e.cap > 0)
{
int flow = dinic(e.v, min(maxflow, e.cap));
if (flow)
{
e.cap -= flow; // 正向边流量降低
es[tab[x][i] ^ 1].cap += flow; // 反向边流量增加
return flow;
}
}
}
return 0; // 找不到增广路 退出
}
int DINIC()
{
int ans = 0;

while (BFS()) // 建立分层图
{
int flow;
memset(current, 0, sizeof(current)); // BFS后应当清空当前弧数组
while (flow = dinic(S, 0x3f3f3f3f)) // 一次BFS可以进行多次增广
ans += flow;
}
return ans;
}

void ori(){

R=0,S=0,T=N+1;
for(int i=0;i<cs;i++)tab[i].clear();
memset(last,-1,sizeof(last));

}

int main(){
// M pig N customer
while(~scanf("%d%d",&M,&N)){
ori();
for(int i=1;i<=M;i++)scanf("%d",&pig[i]);
for(int i=1;i<=N;i++){
scanf("%d",&numA[i]);

for(int j=0;j<numA[i];j++){
int tmp;
scanf("%d",&tmp);
if(last[tmp]==-1)addedge(S,i,pig[tmp]);
else addedge(last[tmp],i,INF);
last[tmp]=i;

}
scanf("%d",&numB[i]);
addedge(i,T,numB[i]);
}

int re=DINIC();
printf("%d\n",re);

}
}


然后我又get到一个新技能,以后RE不要怂,所有的数组都开大,不管题目怎么说,开大数组,开大数组,不要怂......

poj 2135

最小费用流模板题,学学费用流怎么建边

最小费用流是用spfa来写的,反正就难在建图,图建出来了就套模板......

我这里直接用了某人的模板

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <algorithm>
#include <queue>
#define V 10100
#define E 1000100
#define inf 99999999
using namespace std;
int vis[V];
int dist[V];
int pre[V];

struct Edge{
int u,v,c,cost,next;
}edge[E];
int head[V],cnt;

void init(){
cnt=0;
memset(head,-1,sizeof(head));
}
void addedge(int u,int v,int c,int cost)
{
edge[cnt].u=u;edge[cnt].v=v;edge[cnt].cost=cost;
edge[cnt].c=c;edge[cnt].next=head[u];head[u]=cnt++;

edge[cnt].u=v;edge[cnt].v=u;edge[cnt].cost=-cost;
edge[cnt].c=0;edge[cnt].next=head[v];head[v]=cnt++;
}

bool spfa(int begin,int end){
int u,v;
queue<int> q;
for(int i=0;i<=end+2;i++){
pre[i]=-1;
vis[i]=0;
dist[i]=inf;
}
vis[begin]=1;
dist[begin]=0;
q.push(begin);
while(!q.empty()){
u=q.front();
q.pop();
vis[u]=0;
for(int i=head[u];i!=-1;i=edge[i].next){
if(edge[i].c>0){
v=edge[i].v;
if(dist[v]>dist[u]+edge[i].cost){
dist[v]=dist[u]+edge[i].cost;
pre[v]=i;
if(!vis[v]){
vis[v]=true;
q.push(v);
}
}
}
}
}
return dist[end]!=inf;
}

int MCMF(int begin,int end){
int ans=0,flow;
int flow_sum=0;
while(spfa(begin,end)){
flow=inf;
for(int i=pre[end];i!=-1;i=pre[edge[i].u])
if(edge[i].c<flow)
flow=edge[i].c;
for(int i=pre[end];i!=-1;i=pre[edge[i].u]){
edge[i].c-=flow;
edge[i^1].c+=flow;
}
ans+=dist[end];
flow_sum += flow;
}
//cout << flow_sum << endl;
return ans;
}

int main()
{
//freopen("in.txt","r",stdin);
int n,m,a,b,c;
while(scanf("%d%d",&n,&m)!=EOF){
init();
addedge(0,1,2,0);
addedge(n,n+1,2,0);
for(int i=1;i<=m;i++){
scanf("%d%d%d",&a,&b,&c);
addedge(a,b,1,c);
addedge(b,a,1,c);
}
printf("%d\n",MCMF(0,n+1));
}
return 0;
}


poj 2195

建图,不难理解

代码

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <algorithm>
#include <queue>
#define V 10100
#define E 1000100
#define inf 99999999
const int maxn = 100 + 50 ;
using namespace std;
int vis[V];
int dist[V];
int pre[V];
char maze[maxn][maxn];
int dce[maxn][maxn];
struct nd{
int x,y;

};
vector<nd>vh;
vector<nd>vm;
struct Edge{
int u,v,c,cost,next;
}edge[E];
int head[V],cnt;

void init(){
cnt=0;
memset(head,-1,sizeof(head));
}
void addedge(int u,int v,int c,int cost)
{
edge[cnt].u=u;edge[cnt].v=v;edge[cnt].cost=cost;
edge[cnt].c=c;edge[cnt].next=head[u];head[u]=cnt++;

edge[cnt].u=v;edge[cnt].v=u;edge[cnt].cost=-cost;
edge[cnt].c=0;edge[cnt].next=head[v];head[v]=cnt++;
}

bool spfa(int begin,int end){
int u,v;
queue<int> q;
for(int i=0;i<=end+2;i++){
pre[i]=-1;
vis[i]=0;
dist[i]=inf;
}
vis[begin]=1;
dist[begin]=0;
q.push(begin);
while(!q.empty()){
u=q.front();
q.pop();
vis[u]=0;
for(int i=head[u];i!=-1;i=edge[i].next){
if(edge[i].c>0){
v=edge[i].v;
if(dist[v]>dist[u]+edge[i].cost){
dist[v]=dist[u]+edge[i].cost;
pre[v]=i;
if(!vis[v]){
vis[v]=true;
q.push(v);
}
}
}
}
}
return dist[end]!=inf;
}

int MCMF(int begin,int end){
int ans=0,flow;
int flow_sum=0;
while(spfa(begin,end)){
flow=inf;
for(int i=pre[end];i!=-1;i=pre[edge[i].u])
if(edge[i].c<flow)
flow=edge[i].c;
for(int i=pre[end];i!=-1;i=pre[edge[i].u]){
edge[i].c-=flow;
edge[i^1].c+=flow;
}
ans+=dist[end];
flow_sum += flow;
}
//cout << flow_sum << endl;
return ans;
}

int main()
{
//freopen("in.txt","r",stdin);
int n,m,a,b,c;
int M,H;
while(scanf("%d%d",&n,&m)!=EOF&&!(n==0&&m==0)){
M=H=0;
vm.clear();
vh.clear();
for(int i=1;i<=n;i++){
getchar();
for(int j=1;j<=m;j++){
scanf("%c",&maze[i][j]);
if(maze[i][j]=='m'){M++;nd t;t.x=i,t.y=j;vm.push_back(t);}
if(maze[i][j]=='H'){H++;nd t;t.x=i,t.y=j;vh.push_back(t);}
}

}
init();
// deal();
for(int i=1;i<=M;i++)addedge(0,i,1,0);
for(int i=M+1;i<=M+H;i++)addedge(i,M+H+1,1,0);
for(int i=0;i<M;i++){
nd t1=vm[i];
for(int j=0;j<H;j++){
nd t2=vh[j];
int dis=abs(t1.x-t2.x)+abs(t1.y-t2.y);
addedge(i+1,j+M+1,1,dis);
}

}
printf("%d\n",MCMF(0,M+H+1));
}
return 0;
}


poj 2516

题意:有N个客户,M个仓库,和K种货物。已知每个客户需要每种货物的数量,每个仓库存储每种货物的数量,每个仓库运输各种货物去各个客户的单位费用。判断所有的仓库能否满足所有客户的需求,如果可以,求出最少的运输总费用。

构图:K次最小费用最大流。过程中如果有最大流小于总需求则可判不可行。

恩,这是个模板题

#include<cstdio>
#include<cstring>
#include<queue>
#define MAXN 100
#define MAXE 10000
#define INF 0x7fffffff
#define MIN(a,b) a>b?b:a
using namespace std;
int shkp[MAXN][MAXN],supp[MAXN][MAXN],cost[MAXN][MAXN][MAXN];
int head[MAXN],dist[MAXN],vist[MAXN],pre[MAXN],pos[MAXN];
int cnt;
int n,m,k;
int st,ed;
int mincost,maxflow;
struct Edge
{
int to;
int cap;
int cost;
int next;
}edge[MAXE];

void add(int u,int v,int cap,int cost)
{
edge[cnt].to=v;
edge[cnt].cap=cap;
edge[cnt].cost=cost;
edge[cnt].next=head[u];
head[u]=cnt++;

edge[cnt].to=u;
edge[cnt].cap=0;
edge[cnt].cost=-cost;
edge[cnt].next=head[v];
head[v]=cnt++;
}

void MCMF(int st,int ed)
{
int i,u,v;
int aug;
mincost=maxflow=0;
for(;;)
{
memset(vist,0,sizeof(vist));
memset(pre,-1,sizeof(pre));
//memset(dist,INF,sizeof(dist));
//memset赋值时,容易溢出变负数,一晚上错这里了!!!
for(i=0;i<=ed;i++)
dist[i]=INF;
dist[st]=0;
pre[st]=st;
vist[st]=1;
queue<int> q;
q.push(st);
while(!q.empty())
{
u=q.front();
q.pop();
vist[u]=0;
for(i=head[u];i!=-1;i=edge[i].next)
{
v=edge[i].to;
if(edge[i].cap>0&&dist[v]>dist[u]+edge[i].cost)
{
dist[v]=dist[u]+edge[i].cost;
pre[v]=u;
pos[v]=i;
if(!vist[v])
{
vist[v]=1;
q.push(v);
}
}
}
}
//if(pre[ed]==-1)
if(dist[ed]==INF)  //这两个条件是等价的
break;
aug=INF;
for(u=ed;u!=st;u=pre[u])
aug=MIN(aug,edge[pos[u]].cap);
maxflow+=aug;
mincost+=dist[ed]*aug;
for(u=ed;u!=st;u=pre[u])
{
edge[pos[u]].cap-=aug;
edge[pos[u]^1].cap+=aug;
}
}
}

int main()
{
int i,j,r;
int need,totalcost,totalflow;
while(scanf("%d%d%d",&n,&m,&k)!=EOF)
{
if(!n&&!m&&!k)
return 0;
need=0;
totalcost=0;
totalflow=0;
for(i=1;i<=n;i++)
for(j=1;j<=k;j++)
{
scanf("%d",&shkp[i][j]);
need+=shkp[i][j];
}
for(i=1;i<=m;i++)
for(j=1;j<=k;j++)
scanf("%d",&supp[i][j]);
for(r=1;r<=k;r++)
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
scanf("%d",&cost[r][i][j]);
for(r=1;r<=k;r++)
{
cnt=0;
memset(head,-1,sizeof(head));
for(i=1;i<=m;i++)
add(0,i,supp[i][r],0);
for(i=1;i<=n;i++)
add(i+m,m+n+1,shkp[i][r],0);
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
add(j,i+m,INF,cost[r][i][j]);
st=0;
ed=n+m+1;
MCMF(st,ed);
totalcost+=mincost;
totalflow+=maxflow;
}
if(totalflow!=need)
totalcost=-1;
printf("%d\n",totalcost);
}
return 0;
}

http://blog.csdn.net/z309241990/article/details/38531655 http://blog.csdn.net/mypsq/article/details/38467727
这个是进阶(网络流)涉及的比较难
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: