上連接:
初期,比較簡單
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[n];
}
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
這個是進階(網絡流)涉及的比較難