zoukankan      html  css  js  c++  java
  • 【模板】图论

    图的储存
    链式前向星

    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
    ", 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
    ", 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
    ", 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
    ", 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
    ", 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
    ", i);//割点
    
    	for(int i = 1; i <= n; ++i){
    		int f = fa[i];
    		if(f > 0 && dfn[f] < low[i]) printf("%d, %d
    ", 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
    ", 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
    ", cost);
    	return 0;
    }
    
  • 相关阅读:
    声明式事务
    创建索引之代码开发
    Lucene实现全文检索的流程
    9)添加对话框的按键处理消息
    8)添加一个新的非模态对话框
    7)给tab下面添加一个子非模态对话框
    6)对(5)的代码进行一下修改 但是功能不变
    5)添加一个tab
    4)创建一个简单页面
    3)为啥(2)的代码那么写的原因
  • 原文地址:https://www.cnblogs.com/hanser/p/7692623.html
Copyright © 2011-2022 走看看