网络流
2015-11-16 16:03
716 查看
上连接:
初期,比较简单
http://www.cnblogs.com/exponent/archive/2011/11/11/2245324.html
poj 1459
网络流模板题
模板来自kuangbin
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与最大流量是否相等即可。
poj 2112
额,这个题真是做的人心好累
题意:有K台挤奶机(编号1~K),C头奶牛(编号K+1~K+C),给出各点之间距离。现在要让C头奶牛到挤奶机去挤奶,每台挤奶机只能处理M头奶牛,求使所走路程最远的奶牛的路程最短的方案。
构图:先Floyd求所有点对之间最短路,二分最短长度,若奶牛与挤奶机之间的距离大于mid则不连边,否则连容量为1的边。源向挤奶机连容量M的边,奶牛向汇连容量1的边,用最大流判可行性。
问了问逊哥,说求最长路径的最短值,典型的二分特政......
然后在写的过程中也是各种错,我觉得都是些可以避免的错......像把K和C的含义搞反,像少写了<号,还是素养的问题,你自己多反思......
然后近段时间有进步吧,不过写题还是很慢,算了只能慢慢写了,上代码,代码比较不是很好看,用的是DINIC,速度还行......
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,就数组一直在扩......)
以后要随机应变
上代码
poj 1149
题意和题解我已经无心去写了......
然后这个题一直在RE,然后我就把边表使劲开大,使劲开大,然后他妈的的MLE,然后我就不知道怎么办了,总想着是不是我思路错了,就一直纠结纠结......
后来果断问马神,然后他做了一发,然后他和我说是我数组开小了,我还说不可能(因为边表确实开到了最大)
然后他一来,帮我把customer相关量开到了1500,然后就他妈的AC了
我去,题目明明说的是customer不会过100,不会过100,去他妹的题目,真坑人
上代码
然后我又get到一个新技能,以后RE不要怂,所有的数组都开大,不管题目怎么说,开大数组,开大数组,不要怂......
poj 2135
最小费用流模板题,学学费用流怎么建边
最小费用流是用spfa来写的,反正就难在建图,图建出来了就套模板......
我这里直接用了某人的模板
poj 2195
建图,不难理解
代码
poj 2516
题意:有N个客户,M个仓库,和K种货物。已知每个客户需要每种货物的数量,每个仓库存储每种货物的数量,每个仓库运输各种货物去各个客户的单位费用。判断所有的仓库能否满足所有客户的需求,如果可以,求出最少的运输总费用。
构图:K次最小费用最大流。过程中如果有最大流小于总需求则可判不可行。
恩,这是个模板题
http://blog.csdn.net/z309241990/article/details/38531655 http://blog.csdn.net/mypsq/article/details/38467727
这个是进阶(网络流)涉及的比较难
初期,比较简单
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
这个是进阶(网络流)涉及的比较难
相关文章推荐
- 轻松把玩HttpClient之配置ssl,采用设置信任自签名证书实现https
- 不同框架实现的WebService的服务端获取HttpServletRequest的方法
- Heritrix3.3.0源码阅读 URI过滤规则
- BAT解密:互联网技术发展之路(7)- 网络层技术剖析
- HTTPURLConnection中接收数据流
- [Android_机制]_Http和Socket连接区别
- [TCPIP] 传输控制协议 Note
- [TCPIP] 传输控制协议 Note
- [TCPIP] DNS Note
- Http与Socket
- [TCPIP] DNS Note
- [TCPIP] IP路由表及选路 Note
- [TCPIP] IP路由表及选路 Note
- Android 网络通信
- [TCPIP] 分层 Note
- 接口测试培训:HTTP协议基础
- 2015-11-16亲测58可用httpwebrequest模拟登陆方法
- BAT解密:互联网技术发展之路(7)- 网络层技术剖析
- 网路传输模型(osI和tcp/ip)
- Base-Android快速开发框架(四)--网络操作之FastJson以及AsyncHttpClient