zoukankan      html  css  js  c++  java
  • 2020/10/11

    kuangbin网络流4题

    ///链接:https://vjudge.net/problem/UVA-10480
    /*题意: n个结点,m路径,现在让s和t号结点不要连接,破坏一条点的花费为k。
      题解:最小割。但是注意此题有个区别,他是破坏点,所以我们应该拆点,然后在跑。
    */
    
    #include"stdio.h"
    #include"string.h"
    #include"stack"
    #include"map"
    #include"math.h"
    #include"iostream"
    #include"string"
    #include"vector"
    #include"queue"
    #include"algorithm"
    using namespace std;
    #define OK printf("
    ");
    #define Debug printf("this_ok
    ");
    #define INF 1e18
    typedef long long ll;
    #define scanll(a,b) scanf("%lld%lld",&a,&b);
    #define scanl(a) scanf("%lld",&a);
    #define printl(a,b) if(b == 0) printf("%lld ",a); else printf("%lld
    ",a);
    #define print_int(a,b) if(b == 0) printf("%d ",a); else printf("%d
    ",a);
    typedef pair<int,int> PII;
    
    inline int read(){
        int s = 0, w = 1; char ch = getchar();
        while(ch < '0' || ch > '9')   { if(ch == '-') w = -1; ch = getchar(); }
        while(ch >= '0' && ch <= '9') { s = (s << 3) + (s << 1) + (ch ^ 48); ch = getchar(); }
        return s * w;
    }
    const ll mod = 998244353;
    const int N = 200000,M = 800000;
    const  double pi = acos(-1);
    const int inf = 1 << 29;
    const int dirx[4] = {-1,0,1,0};
    const int diry[4] = {0,1,0,-1};
    int n,m,t,s,tot;
    ll maxflow,sum;
    int head[N],ver[M],Next[M],edge[M],d[N];
    int w[N];
    queue<int> q;
    map<string,int> Q;
    void add(int x,int y,int z){
        ver[++ tot] = y; Next[tot] = head[x];  edge[tot] = z; head[x] = tot;
        ver[++ tot] = x; edge[tot] = 0; Next[tot] = head[y]; head[y] = tot;
    }
    void add1(int x,int y,int z){
        ver[++ tot] = y; Next[tot] = head[x];  edge[tot] = z; head[x] = tot;
        ver[++ tot] = x; edge[tot] = 0; Next[tot] = head[y]; head[y] = tot;
    }
    bool bfs(){
        memset(d,0,sizeof(d));
        while(q.size())q.pop();
        q.push(s); d[s] = 1;
        while(q.size()){
            int x = q.front(); q.pop();
            for(int i = head[x]; i; i = Next[i])
            if(edge[i] && !d[ver[i]]){
                q.push(ver[i]); d[ver[i]] = d[x] + 1;
                if(ver[i] == t) return 1;
            }
        }
        return 0;
    }
    
    int dinic(int x,ll flow){
        if(x == t) return flow;
        ll rest = flow,k;
        for(int i = head[x]; i && rest; i = Next[i]){
             if(edge[i] && d[ver[i]] == d[x] + 1){
                k = dinic(ver[i],min(rest,(ll)edge[i]));
                if(!k) d[ver[i]] = 0;
                edge[i] -= k;
                edge[i ^ 1] += k;
                rest -= k;
             }
        }
        return flow - rest;
    }
    int main(){
        while(~scanf("%d",&n)){
            m = read();
            for(int i = 0; i <= n + n + 2; i ++) head[i] = 0;
            tot = 1;s = read(); t = read();t += n;
            for(int i = 1; i <= n; i ++){
                int x = read();
                add1(i,i + n,x);
            }
            for(int i = 1; i <= m; i ++){
               int x = read(),y = read();
               add(x + n,y,inf);
               add(y + n,x,inf);
            }
            ll flow = 0; maxflow = 0;
            while(bfs())
                while(flow = dinic(s,inf)) maxflow += flow;
            printf("%lld
    ",maxflow);
        }
    }
    /*
    3
    1 2 3
    2
    2 6
    */
    
    
    ///链接:https://vjudge.net/problem/UVA-10480
    /*题意: n个结点,m路径,现在让1和2号结点不要连接,破坏一条路径的花费为k。
      题解:最小割,输出路径的话,x和y一开始有路径,x只和1号点连接,y只和2号点连接,那么就是割边。
      鉴于此,本题我们用邻接矩阵存储更为方便;
    */
    
    #include"stdio.h"
    #include"string.h"
    #include"stack"
    #include"map"
    #include"math.h"
    #include"iostream"
    #include"vector"
    #include"queue"
    #include"algorithm"
    using namespace std;
    #define OK printf("
    ");
    #define Debug printf("this_ok
    ");
    #define INF 0x3f3f3f3f
    typedef long long ll;
    #define scanll(a,b) scanf("%lld%lld",&a,&b);
    #define scanl(a) scanf("%lld",&a);
    #define printl(a,b) if(b == 0) printf("%lld ",a); else printf("%lld
    ",a);
    #define print_int(a,b) if(b == 0) printf("%d ",a); else printf("%d
    ",a);
    typedef pair<int,int> PII;
    
    inline int read(){
        int s = 0, w = 1; char ch = getchar();
        while(ch < '0' || ch > '9')   { if(ch == '-') w = -1; ch = getchar(); }
        while(ch >= '0' && ch <= '9') { s = (s << 3) + (s << 1) + (ch ^ 48); ch = getchar(); }
        return s * w;
    }
    const ll mod = 998244353;
    const int N = 500010,M = 500010;
    const int inf = 1 << 29;
    const int maxn=1e3+10;
    int n,m;
    int mp[maxn][maxn];//初始流量
    int flow[maxn][maxn];//最大流
    int path[maxn];//记录路径
    int a[maxn];//i点在最大流中的流量
    int start,End;
    int x[maxn],y[maxn];
    int maxflow()
    {
        queue<int> q;
        memset(flow,0,sizeof flow);
        int max_flow=0;
        while(true){
            memset(a,0,sizeof a);//清空标记
            a[start]=INF;//源点权值无限大
            while(!q.empty())   q.pop();
            q.push(start);
            while(!q.empty()){
                int temp=q.front();
                q.pop();
                for(int i=1;i<=n;i++){
                    //未走过且流量小于他的权值
                    if(!a[i]&&flow[temp][i]<mp[temp][i])
                    {
                        path[i]=temp;//记录前一个点
                        a[i]=min(a[temp],mp[temp][i]-flow[temp][i]);
                        q.push(i);
                    }
                }
    
            }
            if(a[End]==0)   break;
            //更新剩余网络
            for(int i=End;i!=start;i=path[i]){
                flow[path[i]][i]+=a[End];//反向边加
                flow[i][path[i]]-=a[End];//正向边减
            }
            max_flow+=a[End];
        }
        return max_flow;
    }
    int main()
    {
        while(~scanf("%d%d",&n,&m)){
            if(n == 0) break;
            memset(mp,0,sizeof mp);
            for(int i=1;i<=m;i++)
            {
                int u = read(),v = read(),w = read();
                mp[u][v]=mp[v][u]=w;///无向路径
                x[i]=u; y[i]=v;
            }
            start=1;End=2;
            int flow=maxflow();
            for(int i=1;i<=m;i++){//枚举每一条边的两个点
                //有一点的权值为0,说明当前点被删除
                if((!a[x[i]]&&a[y[i]])||(a[x[i]]&&!a[y[i]]))
                printf("%d %d
    ",x[i],y[i]);
            }
            printf("
    ");
        }
        return 0;
    }
    ///链接:http://acm.hdu.edu.cn/showproblem.php?pid=4280
    /*题意: 在最西边的点走到最东边的点最大容量。
      题解:ISAP模板题,Dinic过不了。
    */
    
    #include"stdio.h"
    #include"string.h"
    #include"stack"
    #include"map"
    #include"math.h"
    #include"iostream"
    #include"string"
    #include"vector"
    #include"queue"
    #include"algorithm"
    using namespace std;
    #define OK printf("
    ");
    #define Debug printf("this_ok
    ");
    #define INF 1e18
    typedef long long ll;
    #define scanll(a,b) scanf("%lld%lld",&a,&b);
    #define scanl(a) scanf("%lld",&a);
    #define printl(a,b) if(b == 0) printf("%lld ",a); else printf("%lld
    ",a);
    #define print_int(a,b) if(b == 0) printf("%d ",a); else printf("%d
    ",a);
    typedef pair<int,int> PII;
    
    inline int read(){
        int s = 0, w = 1; char ch = getchar();
        while(ch < '0' || ch > '9')   { if(ch == '-') w = -1; ch = getchar(); }
        while(ch >= '0' && ch <= '9') { s = (s << 3) + (s << 1) + (ch ^ 48); ch = getchar(); }
        return s * w;
    }
    const ll mod = 998244353;
    const int N = 200000,M = 800000;
    const  double pi = acos(-1);
    const int inf = 1 << 29;
    const int dirx[4] = {-1,0,1,0};
    const int diry[4] = {0,1,0,-1};
    int n,m,t,s,tot;
    ll maxflow,sum;
    int head[N],ver[M],Next[M],edge[M],d[N];
    int w[N];
    queue<int> q;
    map<string,int> Q;
    void add(int x,int y,int z){
        ver[++ tot] = y; Next[tot] = head[x];  edge[tot] = z; head[x] = tot;
        ver[++ tot] = x; edge[tot] = z; Next[tot] = head[y]; head[y] = tot;
    }
    
    bool bfs(){
        memset(d,0,sizeof(d));
        while(q.size())q.pop();
        q.push(s); d[s] = 1;
        while(q.size()){
            int x = q.front(); q.pop();
            for(int i = head[x]; i; i = Next[i])
            if(edge[i] && !d[ver[i]]){
                q.push(ver[i]); d[ver[i]] = d[x] + 1;
                if(ver[i] == t) return 1;
            }
        }
        return 0;
    }
    
    int dinic(int x,ll flow){
        if(x == t) return flow;
        ll rest = flow,k;
        for(int i = head[x]; i && rest; i = Next[i]){
             if(edge[i] && d[ver[i]] == d[x] + 1){
                k = dinic(ver[i],min(rest,(ll)edge[i]));
                if(!k) d[ver[i]] = 0;
                edge[i] -= k;
                edge[i ^ 1] += k;
                rest -= k;
             }
        }
        return flow - rest;
    }
    int main(){
        int T = read();
        while(T --){
            n = read(); m = read();
            tot = 1;s = 1; t = 1;
            int tmax = -inf, tmin = inf;
             s = t= 1;
            for(int i = 1; i <= n; i ++) {
                int x = read(),y = read();
                if(x >= tmax) tmax = x, t = i;
                if(x <= tmin) tmin = x, s = i;
                head[i] = 0;
             }
            for(int i = 1; i <= m; i ++){
               int x = read(),y = read(),w = read();
               add(x,y,w);
            }
            ll flow = 0; maxflow = 0;
            while(bfs())
                while(flow = dinic(s,inf)) maxflow += flow;
            printf("%lld
    ",maxflow);
        }
    }
    /*
    3
    1 2 3
    2
    2 6
    #include <cstdio>
    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <string>
    #include <cmath>
    #include <queue>
    #include <vector>
    #include <map>
    #include <set>
    using namespace std;
    #define INF 0x3f3f3f3f
    #define N 100010
    typedef long long LL;
    struct Edge {
        int u, v;
        LL cap;
        Edge () {}
        Edge (int u, int v, LL cap) : u(u), v(v), cap(cap) {}
    }edge[N*4];
    vector<int> G[N];
    int dis[N], cur[N], num[N], pre[N], tot, S, T;
    
    void Add(int u, int v, int cap) {
        edge[tot] = Edge(u, v, cap);
        G[u].push_back(tot++);
        edge[tot] = Edge(v, u, cap);
        G[v].push_back(tot++);
    }
    
    int BFS() { // 逆向BFS
        memset(dis, -1, sizeof(dis));
        queue<int> que; que.push(T);
        dis[T] = 0;
        while(!que.empty()) {
            int u = que.front(); que.pop();
            for(int i = 0; i < G[u].size(); i++) {
                Edge &e = edge[G[u][i]];
                if(dis[e.v] == -1) {
                    dis[e.v] = dis[u] + 1;
                    que.push(e.v);
                }
            }
        }
        return ~dis[S];
    }
    
    int DFS() { // 通过pre数组回溯更新流量
        int u = T; int flow = INF;
        while(u != S) {
            Edge &e = edge[pre[u]];
            if(e.cap < flow) flow = e.cap;
            u = e.u;
        } u = T;
        while(u != S) {
            Edge& e1 = edge[pre[u]];
            Edge& e2 = edge[pre[u]^1];
            e1.cap -= flow; e2.cap += flow;
            u = e1.u;
        }
        return flow;
    }
    
    int ISAP(int n) {
        if(!BFS()) return 0; // 从汇点到源点逆向BFS初始化dis数组
        memset(num, 0, sizeof(num));
        memset(cur, 0, sizeof(cur)); // 当前弧优化
        for(int i = 1; i <= n; i++)
            if(~dis[i]) num[dis[i]]++; // 当前距离为dis[i]的结点数
        int ans = 0, u = S;
        while(dis[S] < n) {
            if(u == T) ans += DFS(), u = S; //  回溯之前的结点并把更新流量
            int flag = 0;
            for(int i = 0; i < G[u].size(); i++) {
                Edge &e = edge[G[u][i]];
                if(dis[e.v] + 1 == dis[u] && e.cap > 0) { // 可以增广
                    pre[e.v] = G[u][i]; cur[u] = i;
                    flag = 1; u = e.v;
                    break;
                }
            }
            if(!flag) { // 不能增广,retreat
                if(--num[dis[u]] == 0) break; // gap优化
                int md = n;
                for(int i = 0; i < G[u].size(); i++) {
                    Edge &e = edge[G[u][i]];
                    if(e.cap > 0 && dis[e.v] < md) {
                        md = dis[e.v]; cur[u] = i;
                    }
                }
                num[dis[u] = md + 1]++;
                if(u != S) u = edge[pre[u]].u;
            }
        }
        return ans;
    }
    
    int main() {
        int t;
        scanf("%d", &t);
        while(t--) {
            int n, m;
            scanf("%d%d", &n, &m);
            tot = 0; for(int i = 0; i <= n; i++) G[i].clear();
            int u, v, c, west = 100000000, east = -10000000;
            for(int i = 1; i <= n; i++) {
                scanf("%d%d", &u, &v);
                if(west > u) west = u, S = i;
                if(east < u) east = u, T = i;
            }
            for(int i = 1; i <= m; i++) {
                scanf("%d%d%d", &u, &v, &c);
                Add(u, v, c); // 无向图的话反向边的cap也是c
            }
            printf("%d
    ", ISAP(n));
        }
        return 0;
    }
    */
    
    ///链接:https://vjudge.net/problem/POJ-1087
    /*题意:  有m个设备需要插座(给出了每个设备需要的插座型号),但是现在只有n个插座(任意两个插座类型不相同,因为题目说每种类型插座就一个),且给你k个转换器(转换器(u,v)可以使得插座v转接到u上),问你最多有几个设备没有插座可用?
      题解:建图:
           源点s(编号0)到每个设备i有边 (s,i,1).
           每个插座到j到汇点t(编号n+m+1)有边 (j,t,1)
           如果设备i对应的插座是j,那么有边(i,j,1)
           如果转换器对应(u,v)(说明可以把插座v转接到u上),那么有边(u,v,INF) (因为转换器无限个,且它可以把原本需要u插座的电器连到v插座上)
    */
    
    #include"stdio.h"
    #include"string.h"
    #include"stack"
    #include"map"
    #include"math.h"
    #include"iostream"
    #include"string"
    #include"vector"
    #include"queue"
    #include"algorithm"
    using namespace std;
    #define OK printf("
    ");
    #define Debug printf("this_ok
    ");
    #define INF 1e18
    typedef long long ll;
    #define scanll(a,b) scanf("%lld%lld",&a,&b);
    #define scanl(a) scanf("%lld",&a);
    #define printl(a,b) if(b == 0) printf("%lld ",a); else printf("%lld
    ",a);
    #define print_int(a,b) if(b == 0) printf("%d ",a); else printf("%d
    ",a);
    typedef pair<int,int> PII;
    
    inline int read(){
        int s = 0, w = 1; char ch = getchar();
        while(ch < '0' || ch > '9')   { if(ch == '-') w = -1; ch = getchar(); }
        while(ch >= '0' && ch <= '9') { s = (s << 3) + (s << 1) + (ch ^ 48); ch = getchar(); }
        return s * w;
    }
    const ll mod = 998244353;
    const int N = 50010,M = 300010;
    const  double pi = acos(-1);
    const int inf = 1 << 29;
    const int dirx[4] = {-1,0,1,0};
    const int diry[4] = {0,1,0,-1};
    int n,m,t,s,tot;
    ll maxflow,sum;
    int head[N],ver[M],Next[M],edge[M],d[N];
    int w[N];
    queue<int> q;
    map<string,int> Q;
    void add(int x,int y,int z){
        ver[++ tot] = y; Next[tot] = head[x];  edge[tot] = z; head[x] = tot;
        ver[++ tot] = x; edge[tot] = 0; Next[tot] = head[y]; head[y] = tot;
    }
    
    bool bfs(){
        memset(d,0,sizeof(d));
        while(q.size())q.pop();
        q.push(s); d[s] = 1;
        while(q.size()){
            int x = q.front(); q.pop();
            for(int i = head[x]; i; i = Next[i])
            if(edge[i] && !d[ver[i]]){
                q.push(ver[i]); d[ver[i]] = d[x] + 1;
                if(ver[i] == t) return 1;
            }
        }
        return 0;
    }
    
    int dinic(int x,ll flow){
        if(x == t) return flow;
        ll rest = flow,k;
        for(int i = head[x]; i && rest; i = Next[i]){
             if(edge[i] && d[ver[i]] == d[x] + 1){
                k = dinic(ver[i],min(rest,(ll)edge[i]));
                if(!k) d[ver[i]] = 0;
                edge[i] -= k;
                edge[i ^ 1] += k;
                rest -= k;
             }
        }
        return flow - rest;
    }
    int main(){
        n = read();
        tot = 1;int top = 0; s = 0; t = 510;
        int p1[120] = {0},p2[120] = {0};
        for(int i = 1; i <= n; i ++){
            char str; cin >> str;
            p1[str - 'A' + 1] ++;
        }
        for(int i = 1; i < 120; i ++){
            if(!p1[i]) continue;
            add(i,t,p1[i]);
        }
        m = read();
        for(int i = 1; i <= m; i ++){
            string name; char str;
            cin >> name >> str;
            p2[str - 'A' + 1] ++;
        }
        for(int i = 1; i < 120; i ++){
            if(!p2[i]) continue;
            add(s,i + 120,p2[i]);
           // add(i + 120,i,inf);
        }
        int q = read();
        for(int i = 1; i <= q; i ++){
            char s1,s2; cin >> s1 >> s2;
            add(s1 - 'A' + 1 + 120,s2 - 'A' + 1 + 120,inf);
        }
       for(int i = 1; i < 120; i ++) add(i + 120,i,inf);
        ll flow = 0;
        while(bfs())
            while(flow = dinic(s,inf)) maxflow += flow;
        printf("%lld
    ",m - maxflow);
    }
    /*
    3
    1 2 3
    2
    2 6
    */
    

      

  • 相关阅读:
    SugarCRM 主表自定义字段日期型
    算法导论46 VLSI芯片测试
    算法导论14.18
    算法导论13.24
    poj1980 Unit Fraction Partition **
    算法导论5.12
    算法导论76 对区间的模糊排序
    红黑树(redblack tree)算法,附AVL树的比较
    poj1856 Sea Battle *
    算法导论42 找出所缺的整数
  • 原文地址:https://www.cnblogs.com/yrz001030/p/13799766.html
Copyright © 2011-2022 走看看