• poj 1273 Drainage Ditches(最大流入门)


    题意:n个池塘,m条水渠,求从第一个池塘到第m个池塘能运送的最大流量;

    思路:裸最大流dicnic算法。建分层图并不断找增广路,直到找不到增广路即为最大流。

    邻接表实现:

    #include <cstdio>
    #include <cstring>
    #include <queue>
    using namespace std;
    #define MAXN 210
    #define INF 0x3f3f3f3f
    struct Edge
    {
        int st, ed;
        int c;
        int next;
    }edge[MAXN << 1];
    int n, m;
    int s, t;
    int ans;
    int e = 0; 
    int head[MAXN];
    int d[MAXN];
    int min(int a, int b)
    {
        return a < b ? a : b;
    }
    void init()
    {
        int i, j;
        int a, b, c; 
        s = 1;   //源点
        t = m;   //汇点
        e = 0;   //边数
        ans = 0;
        memset(head, -1, sizeof(head));
        for(i = 1; i <= n; i++)
        {
            scanf("%d%d%d", &a, &b, &c);
            edge[e].st = a;
            edge[e].ed = b;
            edge[e].c = c;
            edge[e].next = head[a];
            head[a]= e++;
            edge[e].st = b;
            edge[e].ed = a;
            edge[e].next = head[b];
            head[b] = e++;
        }
    }
    int bfs()
    {
        memset(d, -1, sizeof(d));
        queue<int> q;
        d[s] = 0;
        q.push(s);
        int i;
        int cur;
        while(!q.empty())
        {
            cur = q.front();
            q.pop();
            for(i = head[cur]; i != -1; i = edge[i].next)
            {
                if(d[edge[i].ed] == -1 && edge[i].c > 0)
                {
                    d[edge[i].ed] = d[cur] + 1; 
                    q.push(edge[i].ed);
                }    
            }
        }
        if(d[t] < 0)
            return 0;
        return 1;
    }
    int dinic(int x, int flow)
    {
        if(x == t)
            return flow;
        int i, a;
        for(i = head[x]; i != -1; i = edge[i].next)
        {
            if(d[edge[i].ed] == d[x] + 1 && edge[i].c > 0 && (a = dinic(edge[i].ed, min(flow, edge[i].c))))
            {
                edge[i].c -= a;
                edge[i ^ 1].c += a;
                return a;    
            }
        }
        return 0;
    }
    void solve()
    {
        while(scanf("%d%d", &n, &m) != EOF)
        {
            init();
            while(bfs()) //建图,增广
            {
                int increment;
                increment = dinic(1, INF);
                    ans +=  increment; 
            }
            printf("%d
    ", ans);
        }
    }
    int main()
    {
        solve();
        return 0;
    }

    邻接矩阵实现:

    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <iostream>
    #define min(x,y) ((x<y)?(x):(y))
    using namespace std;
    const int MAX=0x5fffffff;//
    int tab[250][250];//邻接矩阵
    int dis[250];//距源点距离,分层图
    int q[2000],h,r;//BFS队列 ,首,尾
    int N,M,ANS;//N:点数;M,边数
    int BFS()  //建分层图
    {
         int i,j;
         memset(dis,0xff,sizeof(dis));//以-1填充
         dis[1]=0;
         h=0;r=1;
         q[1]=1;
         while (h<r)
         {
               j=q[++h];
               for (i=1;i<=N;i++)
                   if (dis[i]<0 && tab[j][i]>0)
                   {
                      dis[i]=dis[j]+1;
                      q[++r]=i;
                   }
         }
         if (dis[N]>0)
            return 1;
         else
            return 0;//汇点的DIS小于零,表明BFS不到汇点
    }
    //Find代表一次增广,函数返回本次增广的流量,返回0表示无法增广
    int find(int x,int low)//Low是源点到现在最窄的(剩余流量最小)的边的剩余流量
    {
        int i,a=0;
        if (x==N)return low;//是汇点
        for (i=1;i<=N;i++)
        if (tab[x][i] >0 //联通
         && dis[i]==dis[x]+1 //是分层图的下一层
         &&(a=find(i,min(low,tab[x][i]))))//能到汇点(a !=  0)
        {
           tab[x][i]-=a;
           tab[i][x]+=a;
           return a;
        }
        return 0;
    
    }
    int main()
    {
        //freopen("ditch.in" ,"r",stdin );
        //freopen("ditch.out","w",stdout);
        int i,j,f,t,flow,tans;
        while (scanf("%d%d",&M,&N)!=EOF){
        memset(tab,0,sizeof(tab));
        for (i=1;i<=M;i++)
        {
            scanf("%d%d%d",&f,&t,&flow);
            tab[f][t]+=flow;
        }
        //
        ANS=0;
        while (BFS())//要不停地建立分层图,如果BFS不到汇点才结束
        {
              while(tans=find(1,0x7fffffff))ANS+=tans;//一次BFS要不停地找增广路,直到找不到为止
        }
        printf("%d
    ",ANS);
        }
    }

     sap算法:(出现断链时直接退出;对当前弧优化)

    #include<iostream>
    #include<cstdio>
    #include<memory.h>
    #include<cmath>
    using namespace std;
    #define MAXN 500
    #define MAXE 40000
    #define INF 0x7fffffff
    long ne,nv,tmp,s,t,index;
    struct Edge{
        long next,pair;
        long v,cap,flow;
    }edge[MAXE];
    long net[MAXN];
    long ISAP()
    {
        long numb[MAXN],dist[MAXN],curedge[MAXN],pre[MAXN];
        long cur_flow,max_flow,u,tmp,neck,i;
        memset(dist,0,sizeof(dist));
        memset(numb,0,sizeof(numb));
        memset(pre,-1,sizeof(pre));
        for(i = 1 ; i <= nv ; ++i)
            curedge[i] = net[i];
        numb[nv] = nv;
        max_flow = 0;
        u = s;
        while(dist[s] < nv)
        {
            /* first , check if has augmemt flow */
            if(u == t)
            {
                cur_flow = INF;
                for(i = s; i != t;i = edge[curedge[i]].v) 
                {  
                    if(cur_flow > edge[curedge[i]].cap)
                    {
                        neck = i;
                        cur_flow = edge[curedge[i]].cap;
                    }
                }
                for(i = s; i != t; i = edge[curedge[i]].v)
                {
                    tmp = curedge[i];
                    edge[tmp].cap -= cur_flow;
                    edge[tmp].flow += cur_flow;
                    tmp = edge[tmp].pair;
                    edge[tmp].cap += cur_flow;
                    edge[tmp].flow -= cur_flow;
                }
                max_flow += cur_flow;
                u = neck;
            }
            /* if .... else ... */
            for(i = curedge[u]; i != -1; i = edge[i].next)
                if(edge[i].cap > 0 && dist[u] == dist[edge[i].v]+1)
                    break;
            if(i != -1)
            {
                curedge[u] = i;
                pre[edge[i].v] = u;
                u = edge[i].v;
            }else{
                if(0 == --numb[dist[u]]) break;
                curedge[u] = net[u];
                for(tmp = nv,i = net[u]; i != -1; i = edge[i].next)
                    if(edge[i].cap > 0)
                        tmp = tmp<dist[edge[i].v]?tmp:dist[edge[i].v];
                dist[u] = tmp + 1;
                ++numb[dist[u]];
                if(u != s) u = pre[u];
            }
        }
        
        return max_flow;
    }
    int main() {
        long i,j,np,nc,m,n;
        long a,b,val;
        long g[MAXN][MAXN];
        while(scanf("%d%d",&ne,&nv)!=EOF)
        {
            s = 1;
            t = nv;
            memset(g,0,sizeof(g));
            memset(net,-1,sizeof(net));
            for(i=0;i<ne;++i)
            {
                scanf("%ld%ld%ld",&a,&b,&val);
                g[a][b] += val;
             }
             for(i=1;i<=nv;++i)
                 for(j = i; j <= nv;++j)
                     if(g[i][j]||g[j][i])
                     {
                         edge[index].next = net[i];
                         edge[index].v = j;
                         edge[index].cap = g[i][j];
                         edge[index].flow = 0;
                         edge[index].pair = index+1;
                         net[i] = index++;
                         edge[index].next = net[j];
                         edge[index].v = i;
                         edge[index].cap = g[j][i];
                         edge[index].flow = 0;
                         edge[index].pair = index-1;
                         net[j] = index++;
                     }
            printf("%ld
    ",ISAP());
        }
        return 0;
    }
    View Code
  • 相关阅读:
    WEB前端工程师 – 职业生涯规划
    求Sn=a+aa+aaa+…+aaa…a的值
    输入一行字符,分别统计出其中英文字母 空格 数字和其他字符的个数
    getchar()的用法!
    求1+2+…+n的和不大于1000的最大自然数n
    编程打印输出*金字塔
    从键盘输入一个整数,判断该数是否回文数.
    编程求"水仙花数"
    编程求出1000以内的完全数
    输入两个正整数,求它们的最大公约数和最小公倍数.
  • 原文地址:https://www.cnblogs.com/dashuzhilin/p/4641100.html
Copyright © 2020-2023  润新知