博客园 首页 私信博主 显示目录 隐藏目录 管理

【模板】图论

图的储存
链式前向星

void add(int x, int y, int z){
	to[++e] = y; nxt[e] = begin[x]; w[e] = z; begin[x] = e;
//  to[++e] = x; nxt[e] = begin[y]; w[e] = z; begin[y] = e;	无向图
}

//遍历
当前节点为u
for(int i = begin[u]; i; i = nxt[i]){
	int v = to[i], w_ = w[i];
}

(以下复杂度对比来自网络,侵权即删!)
Dijkstra:O(n2)适用于权值为非负的图的单源最短路径,用斐波那契堆的复杂度O(E+VlgV),
BellmanFord:适用于权值有负值的图的单源最短路径,并且能够检测负圈,复杂度O(VE)
SPFA:适用于权值有负值,且没有负圈的图的单源最短路径,论文中的复杂度O(kE),k为每个节点进入Queue的次数,且k一般<=2,但此处的复杂度证明是有问题的,其实SPFA的最坏情况应该是O(VE).
Floyd:每对节点之间的最短路径。Floyd-Warshall算法的时间复杂度为O(N3),空间复杂度为O(N2)。

先给出结论:
(1)当权值为非负时,用Dijkstra。
(2)当权值有负值,且没有负圈,则用SPFA,SPFA能检测负圈,但是不能输出负圈。
(3)当权值有负值,而且可能存在负圈,则用BellmanFord,能够检测并输出负圈。
(4)SPFA检测负环:当存在一个点入队大于等于V次,则有负环。

最短路
dijkstra(朴素)

#include<bits/stdc++.h>

using namespace std;

const int oo = 2147483647;
const int N = 10010;
const int M = 500010;

int n, m, s, e;
int dis[N], vis[N];
int to[M*2], nxt[M*2], wht[M*2], begin[N];

template <typename T>
T read(){
    T N(0), F(1);
    char C = getchar();
    for(; !isdigit(C); C = getchar()) if(C == '-') F = -1;
    for(; isdigit(C); C = getchar()) N = N*10 + C-48;
    return N*F;
}

void add(int x, int y, int z){
    to[++e] = y; nxt[e] = begin[x]; wht[e] = z; begin[x] = e;
//    to[++e] = x; nxt[e] = begin[y]; wht[e] = z; begin[y] = e;
}

void dijkstra(int st){	
	for(int i = 1; i <= n; i++){
		int mx = oo, u = -1;
		for(int j = 1; j <= n; j++){
			if(!vis[j] && dis[j] < mx){
				mx = dis[j];
				u = j;
			}
		}
		if(u == -1 || mx == oo) break;
		vis[u] = 1;
		for(int j = begin[u]; j; j = nxt[j]){//松弛
			int v = to[j];
			if(!vis[v] && dis[v] > (dis[u] + wht[j]))
				dis[v] = dis[u] + wht[j];
		}
	}

}

int main(){
	n = read<int>(); m = read<int>(); s = read<int>();

	for(int i = 1; i <= n; i++) dis[i] = oo;
	dis[s] = 0;

	for(int i = 1; i <= m; i++){
		int x, y, z;
		x = read<int>(); y = read<int>(); z = read<int>();
		add(x, y, z);
	}
	
	dijkstra(s);

	for(int i = 1; i <= n; i++) printf("%d ", dis[i]);

	return 0;
}

dijkstra(优先队列优化)//希望不要有人嘲讽我真的觉得这是仿spfa套dijk理论搞的

#include<bits/stdc++.h>
#define pb push_back

using namespace std;

const int oo = 2147483647;
const int N = 10010;
const int M = 500010;

int n, m, s;
int dis[N], vis[N];

template <typename T>
T read(){
    T N(0), F(1);
    char C = getchar();
    for(; !isdigit(C); C = getchar()) if(C == '-') F = -1;
    for(; isdigit(C); C = getchar()) N = N*10 + C-48;
    return N*F;
}

struct node{
	int v, w;
	node(){}
	node(int a, int b){v = a; w = b;}
	bool operator < (const node & a) const{
		if(w == a.w) return v < a.v;
		return w > a.w;
	}
};

vector<node> E[N];

priority_queue<node> Q;

void dijkstra(int s){
	for(int i = 1; i <= n; i++) dis[i] = oo;
	dis[s] = 0;
	Q.push(node(s, dis[s]));
	while(!Q.empty()){
		node x = Q.top(); Q.pop();
		for(int i = 0; i < E[x.v].size(); i++){
			node y = E[x.v][i];
			if(dis[y.v] > x.w + y.w){
				dis[y.v] = x.w + y.w;
				Q.push(node(y.v, dis[y.v]));
			}
		}
	}
}

int main(){
	n = read<int>(); m = read<int>(); s = read<int>();

	for(int i = 1; i <= n; i++) dis[i] = oo;
	dis[s] = 0;

	for(int i = 1; i <= m; i++){
		int x, y, z;
		x = read<int>(); y = read<int>(); z = read<int>();
		E[x].pb(node(y, z));
//		E[y].pb(node(x, z));
	}
	
	dijkstra(s);

	for(int i = 1; i <= n; i++) printf("%d ", dis[i]);

	return 0;
}

SPFA

#include<bits/stdc++.h>

using namespace std;

const int oo = 2147483647;
const int N = 10010;
const int M = 500010;

int n, m, s, e;
int dis[N], vis[N];
int to[M*2], nxt[M*2], wht[M*2], begin[N];

template <typename T>
T read(){
    T N(0), F(1);
    char C = getchar();
    for(; !isdigit(C); C = getchar()) if(C == '-') F = -1;
    for(; isdigit(C); C = getchar()) N = N*10 + C-48;
    return N*F;
}

void add(int x, int y, int z){
    to[++e] = y; nxt[e] = begin[x]; wht[e] = z; begin[x] = e;
//    to[++e] = x; nxt[e] = begin[y]; wht[e] = z; begin[y] = e;
}

void init(){
    for(int i = 1; i <= n; i++) dis[i] = oo, vis[i] = 1;
    dis[s] = vis[s] = 0;
}

queue<int> Q;
void spfa(){
    Q.push(s);
    while(!Q.empty()){
        int u = Q.front();
        Q.pop(); vis[u] = 1;
        for(int i = begin[u]; i; i = nxt[i]){
            int v = to[i], w = wht[i];
            if(dis[u] + w < dis[v]){
                dis[v] = dis[u] + w;
                if(vis[v]){
                    Q.push(v);
                    vis[v] = 0;
                }
            }
        }
    }
}

int main(){
    n = read<int>(); m = read<int>(); s = read<int>();
    for(int i = 1; i <= m; i++){
        int x, y, z;
        x = read<int>(); y = read<int>(); z = read<int>();
        add(x, y, z);
    }

    init(); 
    spfa();

    for(int i = 1; i <= n; i++) printf("%d ", dis[i]);

    return 0;
}

Bellman_Ford
[没写过,暂时贴一个别人的,如侵权即删!]

实现简单,复杂度 \(O(|V|*|E|)\)

bool Bellman_Ford(s){
  memset(d,INF,sizeof(INF));
  for(int i=0 ; i<nv ; ++i){
    for(int j=0 ; j<E.size() ; ++j)
    d[E[i].to] = min(d[E[i].to],d[E[i].from]+E[i].weight);
  }
  //负环判定
  for(int i=0 ; i<E.size() ; ++i){
    if(d[E[i].to]<d[E[i].from]+E[i].weight)return false;
  }
  return true;
}

次短路
正向spfa+反向spfa然后每次提出一条边判断次短路。

#include<bits/stdc++.h>

using namespace std;

const int oo = 2147483647;
const int N = 5005;
const int M = 100005;

template <typename T>
T read(){
	T n(0), f(1);
	char ch = getchar();
	for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
	for(; isdigit(ch); ch = getchar()) n = n*10 + ch-48;
	return n*f;
}

int n, m, e, ans, tmp;
int begin[N], dl[N], dr[N], vis[N];
struct node{
	int to, w, nxt;
}E[M>>1];

void add(int x, int y, int z){
	E[++e].to = y; E[e].w = z; E[e].nxt = begin[x]; begin[x] = e;
	E[++e].to = x; E[e].w = z; E[e].nxt = begin[y]; begin[y] = e;
}

void spfa(int s, int d[]){
	for(int i = 1; i <= n; i++) d[i] = oo, vis[i] = 0;
	vis[s] = 1; d[s] = 0;
	
	queue<int> Q;
	Q.push(s);

	while(!Q.empty()){
		int u = Q.front(); Q.pop();
		vis[u] = 0;

		for(int i = begin[u]; i; i = E[i].nxt){
			int v = E[i].to;
			if(!vis[v]){
				if(d[v] > d[u]+E[i].w){
					d[v] = d[u] + E[i].w;
					vis[v] = 1;
					Q.push(v);
				}
			}
		}
	}
}

int main(){	
	n = read<int>(); m = read<int>();
	for(int i = 1; i <= m; i++){
		int x, y, z;
		x = read<int>(); y = read<int>(); z = read<int>();
		add(x, y, z);
	}


	spfa(1, dl);
	spfa(n, dr);

	ans = oo;
	for(int u = 1; u <= n; u++){
		for(int i = begin[u]; i; i = E[i].nxt){
			int v = E[i].to;
			int w_ = E[i].w;
			tmp = dl[u] + dr[v] + w_;
			if(tmp > dl[n] && ans > tmp) ans = tmp;
		}
	}	

	printf("%d\n", ans);
	return 0;
}

多源最短路径(点对之间的最短路)

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cstring>

#define MAXN (100+10)
#define INF 0x3f3f3f3f
int edge[MAXN][MAXN];

int n;

int main(){
	while(scanf("%d", &n) && n){
		int ans = INF, num;
		memset(edge, INF, sizeof(edge));
		for(int i = 1; i <= n; i++){
			int t;
		    scanf("%d", &t);
		    while(t--){
		    	int j, w;
			    scanf("%d%d", &j, &w);
			    edge[i][j] = w;
			}
		}
		for(int k = 1; k <= n; k++)
		    for(int i = 1; i <= n; i++)
		    	for(int j = 1; j <= n; j++)
		    	    if(edge[i][k] + edge[k][j] < edge[i][j]) edge[i][j] = edge[i][k]+edge[k][j];
		
		
		for(int i = 1; i <= n; i++){
			int tmp = 0;
		    for(int j = 1; j <= n; j++){
			    if(i == j) continue;
				if(edge[i][j] > tmp){
				    tmp = edge[i][j];
				}
			}
			if(ans > tmp){
			    ans = tmp, num = i;
			}
		}
		printf("%d %d\n", num, ans);
	}
	return 0;
}

最小生成树

#include<bits/stdc++.h>

using namespace std;

const int N = 5010;
const int M = 200010;

int n, m, ans;
int r[N], f[N];
struct node{
    int u, v, w;
}E[M];

template <typename T>
T read(){
    T N(0), F(1);
    char C = getchar();
    for(; !isdigit(C); C = getchar()) if(C == '-') F = -1;
    for(; isdigit(C); C = getchar()) N = N*10 + C-48;
    return N*F;
}

bool cmp(node x, node y){
    return x.w < y.w;
}

void init(){
    for(int i = 1; i <= n; i++) f[i] = i;
    memset(r, 0, sizeof(r));
}

int find(int x){
    return x == f[x] ? x : f[x] = find(f[x]);
}

void mix(int a, int b){
    int fa = find(f[a]);
    int fb = find(f[b]);
    if(fa == fb) return;
    if(r[fa] < r[fb]){
        f[fa] = fb;
    }
    else{
        f[fb] = fa;
        if(r[fa] == r[fb]) r[fa]++;
    }
}

int krus(){
    int em = 0;
    sort(E+1, E+m+1, cmp);

    for(int i = 1; i <= m && em != n-1; i++){
        int fu = find(E[i].u);
        int fv = find(E[i].v);
        if(find(E[i].u) != find(E[i].v)){
            mix(E[i].u, E[i].v);
            ans += E[i].w;
            em++;
        }
    }
    if(em < n-1) ans = -1;
    return ans;
}

int main(){
    n = read<int>(); m = read<int>();

    for(int i = 1; i <= m; i++){
        E[i].u = read<int>();
        E[i].v = read<int>();
        E[i].w = read<int>();
    }

    init();
    printf("%d\n", krus());

    return 0;
}

有向图Tarjan求scc个数
hdu1269 scc个数为1输出Yes,否则No.

#include<bits/stdc++.h>

using namespace std;

const int N = 10010;

template <typename T>
T read(){
	T n(0), f(1);
	char ch = getchar();
	for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
	for(; isdigit(ch); ch = getchar()) n = n*10 + ch-48;
	return n*f;
}

int n, m, cnt, tot, top;
int dfn[N], low[N], st[N], vis[N];
vector<int> E[N];

void chkmn(int &a, int b){
	a = a < b ? a : b;
}

void init(){
	cnt = top = tot = 0;
	for(int i = 1; i <= n; ++i){
		dfn[i] = -1;
		vis[i] = 0;
	}
	for(int i = 1; i <= n; ++i) E[i].clear();
}

void Tarjan(int u){
	vis[u] = 1;
	dfn[u] = low[u] = ++tot;
	st[++top] = u;
	for(int i = 0; i < E[u].size(); ++i){
		int v = E[u][i];
		if(dfn[v] == -1){
			Tarjan(v);
			chkmn(low[u], low[v]);
		}
		else if(vis[v]) chkmn(low[u], dfn[v]);
	}
	int v_;
	if(dfn[u] == low[u]){
		++cnt;
		do{
			v_ = st[top--];
			vis[v_] = 0;
		}while(u != v_);
	}
}

int main(){
	while(scanf("%d%d", &n, &m)!=EOF){
		if(!n && !m) break;

		init();
		for(int i = 1; i <= m; ++i){
			int x, y;
			x = read<int>(); y = read<int>();
			E[x].push_back(y);
		}

		for(int i = 1; i <= n; ++i)
			if(dfn[i] == -1) Tarjan(i);
		if(cnt == 1) puts("Yes");
		else puts("No");
	}

	return 0;
}

有向图Tarjan求scc内最小权值和
hdu1827 RT

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<vector>
using namespace std;

const int N = 2010;

template <typename T>
T read(){
	T n(0), f(1);
	char ch = getchar();
	for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
	for(; isdigit(ch); ch = getchar()) n = n*10 + ch-48;
	return n*f;
}

int n, m, cnt, tot, top;
int dfn[N], low[N], st[N], vis[N], sccw[N], deg[N], f[N], w[N];
vector<int> E[N], G[N];

void chkmn(int &a, int b){
	a = a < b ? a : b;
}

void init(){
	cnt = top = tot = 0;
	for(int i = 0; i <= n; ++i){
		dfn[i] = -1;
		vis[i] = f[i] = 0;
		deg[i] = 0;
		sccw[i] = 2147483647;
	}
	for(int i = 0; i <= n; ++i) E[i].clear(), G[i].clear();
}

void Tarjan(int u){
	vis[u] = 1;
	dfn[u] = low[u] = ++tot;
	st[++top] = u;
	for(int i = 0; i < E[u].size(); ++i){
		int v = E[u][i];
		if(dfn[v] == -1){
			Tarjan(v);
			chkmn(low[u], low[v]);
		}
		else if(vis[v]) chkmn(low[u], dfn[v]);
	}
	int v_;
	if(dfn[u] == low[u]){
		++cnt; sccw[cnt] = w[u];
		do{
			v_ = st[top--];
			vis[v_] = 0;
			f[v_] = cnt;
			chkmn(sccw[cnt], w[v_]);
		}while(u != v_);
	}
}

int main(){
	while(scanf("%d%d", &n, &m)==2){
		init();
		for(int i = 1; i <= n; ++i) w[i] = read<int>();
		for(int i = 1; i <= m; ++i){
			int x, y;
			x = read<int>(); y = read<int>();
			E[x].push_back(y);
		}

		for(int i = 1; i <= n; ++i)
			if(dfn[i] == -1) Tarjan(i);
		
		for(int i = 1; i <= n; ++i){
			for(int j = 0; j < E[i].size(); ++j){
				if(f[i] != f[E[i][j]]){
					G[f[i]].push_back(f[E[i][j]]);
					deg[f[E[i][j]]]++;
				}
			}
		}
		int ans1 = 0, ans2 = 0;
		for(int i = 1; i <= cnt; ++i){
			if(!deg[i]){
				ans1++;
				ans2 += sccw[i];
			}
		}
		printf("%d %d\n", ans1, ans2);
	}

	return 0;
}

有向图Tarjan缩点求路径点权和最大
模板P3387 缩点+DP(我写的spfa跑路径而非DP计算)

#include<bits/stdc++.h>

using namespace std;

const int N = 10010;
const int M = 100010;

template<typename T>
T read(){
	T n(0), f(1);
	char ch = getchar();
	for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
	for(; isdigit(ch); ch = getchar()) n = n*10 + ch-48;
	return n*f;
}
#define read() read<int>()
#define pb push_back

int n, m, cnt, top, tot;
int dfn[N], val[N], low[N], sccw[N], f[N], vis[N], st[N];
vector<int> E[N];

void chkmx(int& a, int b){
	a = a > b ? a : b;
}
void chkmn(int& a, int b){
	a = a < b ? a : b;
}


void Tarjan(int u){
	dfn[u] = low[u] = ++tot;
	vis[u] = 1; st[++top] = u;
	for(int i = 0; i < E[u].size(); ++i){
		int v = E[u][i];
		if(dfn[v] == -1){
			Tarjan(v);
			chkmn(low[u], low[v]);
		}
		else if(vis[v]) chkmn(low[u], dfn[v]);
	}

	int v_ = 0;
	if(low[u] == dfn[u]){
		++cnt;
		do{
			v_ = st[top--];
			vis[v_] = 0;
			f[v_] = cnt;
			sccw[cnt] += val[v_];
		}while(u != v_);	
	}
}

int e, ans;
int dis[N], bl[N], to[M<<1], nxt[M<<1], Begin[N];

void addedge(int x, int y){
	to[++e] = y; nxt[e] = Begin[x]; Begin[x] = e;
}

void spfa(int s){
	queue<int> Q;
	Q.push(s); bl[s] = 1; dis[s] = sccw[s];
	while(!Q.empty()){
		int u = Q.front(); Q.pop();
		bl[u] = 0;
		for(int i = Begin[u]; i; i = nxt[i]){
			int v = to[i];
			chkmx(dis[v], dis[u]+sccw[v]);
			if(!bl[v]){
				Q.push(v);
				bl[v] = 1;
			}
		}
	}
	for(int i = 1; i <= cnt; ++i) chkmx(ans, dis[i]);
}

int deg[N];

int main(){
	n = read(); m = read();
	for(int i = 1; i <= n; ++i) val[i] = read(), dfn[i] = -1;
	for(int i = 1; i <= m; ++i){
		int x, y;
		x = read();
		y = read();	
		E[x].pb(y);
	}
	
	for(int i = 1; i <= n; ++i)
		if(dfn[i] == -1) Tarjan(i);

	for(int i = 1; i <= n; ++i){
		for(int j = 0; j < E[i].size(); ++j){
			if(f[i] != f[E[i][j]]){
				addedge(f[i], f[E[i][j]]);
				++deg[f[E[i][j]]];
			}
		}
	}
	for(int i = 1; i <= cnt; ++i){
		if(!deg[i]) spfa(i);
	}
	printf("%d\n", ans);
	return 0;
}

无向图Tarjan求割点和桥
[割点] 根节点子树>=2则为割点; 非根节点u的子节点v中,low[v]>=dfn[u]则为割点。
[桥] 节点u的子节点v中,low[v] > dfn[u]则(u, v)为桥。

板子:

#include<bits/stdc++.h>

using namespace std;

const int N = 1e5+10;

template<typename T> T read(){
	T n(0), f(1);
	char ch = getchar();
	for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
	for(; isdigit(ch); ch = getchar()) n = n*10 + ch-48;
	return n*f;
}

int n, m, cnt;
int vis[N], dfn[N], low[N], fa[N];
vector<int> G[N];

void init(){
	for(int i = 1; i <= n; ++i){
		dfn[i] = low[i] = 0;
		fa[i] = 0;
		vis[i] = false;
	}
}

void Tarjan(int u, int f = 0){
	fa[u] = f;
	dfn[u] = low[u] = ++cnt;
	for(int i = 0; i < G[u].size(); ++i){
		int v = G[u][i];
		if(!dfn[v]){
			Tarjan(v, u);
			low[u] = min(low[u], low[v]);
		}
		else if(v != f)
			low[u] = min(low[u], dfn[v]);
	}
}

int main(){
	n = read<int>(); m = read<int>();
	for(int i = 1; i <= m; ++i){
		int x, y;
		x = read<int>();
		y = read<int>();
		G[x].push_back(y);
		G[y].push_back(x);
	}
	init();
	Tarjan(1);

	
	for(int i = 2; i <= n; ++i){
		int f = fa[i];
		if(dfn[f] <= low[i]) vis[f] = true;
	}

	if(G[1].size() > 1) vis[1] = true;
	
	for(int i = 1; i <= n; ++i) if(vis[i]) printf("%d\n", i);//割点

	for(int i = 1; i <= n; ++i){
		int f = fa[i];
		if(f > 0 && dfn[f] < low[i]) printf("%d, %d\n", f, i);//桥
	}
	return 0;
}

网络流

增广路算法求最大流
模板LG P3376
DFS太慢,EK算法其实也很慢....(既然是NOIP选手不掌握fastest也没问题吧)

#include<bits/stdc++.h>

using namespace std;

const int oo = 0x7f7f7f7f;
const int N = 10010;

template <typename T>
T read(){
	T n(0), f(1);
	char ch = getchar();
	for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
	for(; isdigit(ch); ch = getchar()) n = n*10 + ch-48;
	return n*f;
}

struct Edge{
	int u, v, cap, flow;
	Edge(int from, int to, int c, int f):u(from), v(to), cap(c), flow(f){}
};

int n, m;
int a[N], p[N];
vector<Edge> edges;
vector<int> G[N];

#define pb push_back

void init(){
	for(int i = 1; i <= n; ++i) G[i].clear();
	edges.clear();
}

void addedge(int u, int v, int cap){
	edges.pb(Edge(u, v, cap, 0));
	edges.pb(Edge(v, u, 0, 0));
	int tm = edges.size();
	G[u].pb(tm-2);
	G[v].pb(tm-1);
}

int EK(int s, int t){
	int flow = 0;
	for(;;){
		memset(a, 0, sizeof(a));
		queue<int> Q;
		Q.push(s);
		a[s] = oo;
		while(!Q.empty()){
			int x = Q.front(); Q.pop();
			for(int i = 0; i < G[x].size(); ++i){
				Edge& e = edges[G[x][i]];
				if(!a[e.v] && e.cap > e.flow){
					p[e.v] = G[x][i];
					a[e.v] = min(a[x], e.cap-e.flow);
					Q.push(e.v);
				}
			}
			if(a[t]) break;
		}
		if(!a[t]) break;
		for(int i = t; i != s; i = edges[p[i]].u){
			edges[p[i]].flow += a[t];
			edges[p[i]^1].flow -= a[t];
		}
		flow += a[t];
	}
	return flow;
}

int main(){
	int s, t;
	n = read<int>(); m = read<int>();
	s = read<int>(); t = read<int>();

	init();
	
	for(int i = 1; i <= m; ++i){
		int u, v, w;
		u = read<int>();
		v = read<int>();
		w = read<int>();
		addedge(u, v, w);
	}
	
	printf("%d\n", EK(s, t));
	
	return 0;
}

最小费用最大流
模板LG P3381
用Bellmanford求

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
const int N = 5010;
const int M = 50010;
const int oo = 0x7f7f7f7f;

template <typename T>
T read(){
	T n(0), f(1);
	char ch = getchar();
	for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
	for(; isdigit(ch); ch = getchar()) n = n*10 + ch-48;
	return n*f;
}

#define read() read<int>()

struct Edge{
	int from, to, cap, flow, cost;
	Edge(int u, int v, int c, int f, int val):from(u), to(v), cap(c), flow(f), cost(val){}
};

int n, m;
vector<Edge> edges;
vector<int> G[N];
int a[N], d[N], p[N], inq[N];

#define pb push_back

void addedge(int x, int y, int w, int v){
	edges.pb(Edge(x, y, w, 0, v));
	edges.pb(Edge(y, x, 0, 0, -v));
	int tm = edges.size();
	G[x].pb(tm-2);
	G[y].pb(tm-1);
}

void init(){
	for(int i = 1; i <= n; ++i) G[i].clear();
	edges.clear();
}

bool BMFD(int s, int t, int& flow, ll& cost){
	memset(inq, 0, sizeof(inq));
	for(int i = 1; i <= n; ++i) d[i] = oo;
	d[s] = p[s] = 0; a[s] = oo; inq[s] = 1;

	queue<int> Q;
	Q.push(s);
	while(!Q.empty()){
		int u = Q.front(); Q.pop();
		inq[u] = 0;
		for(int i = 0; i < G[u].size(); ++i){
			Edge& e = edges[G[u][i]];
			if(e.cap > e.flow && d[e.to] > d[u]+e.cost){
				d[e.to] = d[u] + e.cost;
				a[e.to] = min(a[u], e.cap-e.flow);
				p[e.to] = G[u][i];
				if(!inq[e.to]){ Q.push(e.to); inq[e.to] = 1; }
			}
		}
	}
	if(d[t] == oo) return false;
	flow += a[t];
	cost += 1ll*d[t]*a[t];
	for(int i = t; i != s; i = edges[p[i]].from){
		edges[p[i]].flow += a[t];
		edges[p[i]^1].flow -= a[t];
	}
	return true;
}

int MCMF(int s, int t, ll& cost){
	int flow = 0; cost = 0;
	while(BMFD(s, t, flow, cost));
	return flow;
}

int main(){
	int s, t;

	n = read(); m = read();
	s = read(); t = read();
	init();
	
	for(int i = 1; i <= m; ++i){
		int x, y, w, v;
		x = read(); y = read();
		w = read(); v = read();
		addedge(x, y, w, v);
	}

	ll cost = 0;
	printf("%d ", MCMF(s, t, cost));
	printf("%lld\n", cost);
	return 0;
}
posted @ 2017-10-19 15:11  Hanser  阅读(150)  评论(0编辑  收藏  举报