zoukankan      html  css  js  c++  java
  • ZOJ1994有源汇上下界可行流

    http://fastvj.rainng.com/contest/236779#problem/G

    Description:

      n 行 m 列

      给你行和 与 列和

      然后有Q个限制,表示特定单元格元素大小的范围,最后问你可行的矩阵值

    Solution:
      有源汇上下界最大流问题,初始源点 连 行和流量是该行对应得行和,然后列连初始汇点,容量为列的列和,详细的限制,对应于行列之间,因为我最后要输出一个矩阵,所以n * m每一条边都要链接最后,手动连一条 t s inf的边,变成无源汇有上下界可行流问题,然后拆边,把对应边的流量,放到数组里,输出就好啦

    Code:

      前面比较基础的Dinic,数据操作函数,加边操作

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #include <queue>
    #define inf (1 << 28)
    using namespace std;
    const int maxn = 25;
    const int maxm = 210;
    const int mn = 505;
    const int mm = 440020;
    struct node{
        int to,val,pre,lid;
    }e[mm];
    int id[mn],cnt=0;
    
    int cur[mn];
    int flor[mn];
    
    int upflow[mn];
    int lowf[maxm][maxn];
    int upf[maxm][maxn];
    int out[maxm][maxn];
    void init()
    {
        memset(id,-1,sizeof(id));
        memset(upflow,0,sizeof(upflow));
        cnt = 0;
    }
    void add(int from,int to,int val,int lid)
    {
        e[cnt].to = to;
        e[cnt].val = val;
        e[cnt].lid = lid;
        e[cnt].pre = id[from];
        id[from] = cnt++;
        swap(from,to);
        e[cnt].to = to;
        e[cnt].val = 0;
        e[cnt].lid = lid;
        e[cnt].pre = id[from];
        id[from] = cnt++;
    }
    void addflow(int from,int to,int low,int up,int lid)
    {
        upflow[from] -= low;
        upflow[to] += low;
        add(from,to,up-low,lid);
    }
    bool bfs(int s,int t)
    {
        memset(flor,0,sizeof(flor));
        flor[s] = 1;
        queue<int> q;
        while(q.size())q.pop();
    
        q.push(s);
        while(q.size())
        {
            int now = q.front();
            q.pop();
    
            for(int i = id[now];~i;i = e[i].pre)
            {
                int to = e[i].to;
                int val = e[i].val;
                if(val > 0 && flor[to] == 0)
                {
                    flor[to] = flor[now] + 1;
                    q.push(to);
                    if(to == t)
                        return true;
                }
            }
        }
        return false;
    }
    int dfs(int s,int t,int value)
    {
        if(s == t || value == 0)return value;
    
        int ret = value,a;
    
        for(int &i = cur[s];~i;i = e[i].pre)
        {
            int val = e[i].val;
            int to = e[i].to;
            if(flor[to] == flor[s] + 1 && (a = dfs(to,t,min(ret,val))))
            {
                e[i].val -= a;
                e[i^1].val += a;
                ret -= a;
                if(ret == 0)break;
            }
        }
        if(ret == value)flor[s] = 0;
        return value - ret;
    }
    
    int Dinic(int s,int t)
    {
        int ret = 0;
        while(bfs(s,t))
        {
            memcpy(cur,id,sizeof(id));
            ret += dfs(s,t,inf);
        }
        return ret;
    }
    
    void addlimit(int i,int j,char op,int lim)
    {
        if(op == '=')
        {
            upf[i][j] = lowf[i][j] = lim;
        }
        else if(op == '>')
        {
            lowf[i][j] = max(lowf[i][j],lim+1);
        }
        else
        {
            upf[i][j] = min(upf[i][j],lim-1);
        }
    }
    

     然后根据输入一点点的加边,这是行和和列和对应的边

    scanf("%d%d",&n,&m);
            s = 0;
            t = n + m + 1;
            ss = t + 1;
            tt = ss + 1;
            int lsum;
            for(int i = 1;i <= n;++i)
            {
                scanf("%d",&lsum);
                addflow(s,i,lsum,lsum,0);
            }
            for(int i = 1;i <= m;++i)
            {
                scanf("%d",&lsum);
                addflow(n + i,t,lsum,lsum,0);
            }
            int limitnum;
    

     然后根据题目中给出的限制条件,填充上下界数组

    scanf("%d",&limitnum);
            for(int i = 1;i <= n;++i)
            {
                for(int j = 1;j <= m;++j)
                {
                    lowf[i][j] = 0;
                    upf[i][j] = inf;
                }
            }
            int row,col,lim;
            char op;
            for(int i = 1;i <= limitnum;++i)
            {
                scanf("%d %d %c %d",&row,&col,&op,&lim);
                if(row == 0 && col == 0)
                {
                    for(int i = 1;i <= n;++i)
                    {
                        for(int j = 1;j <= m;++j)
                        {
                            addlimit(i,j,op,lim);
                        }
                    }
                }
                else if(row == 0)
                {
                    for(int i = 1;i <= n;++i)
                    {
                        addlimit(i,col,op,lim);
                    }
                }
                else if(col == 0)
                {
                    for(int i = 1;i <= m;++i)
                    {
                        addlimit(row,i,op,lim);
                    }
                }
                else
                {
                    addlimit(row,col,op,lim);
    
                }
            }
    

     根据上下界数组,添加有上下界边

    int tot = 0;
            for(int i = 1;i <= n;++i)
            {
                for(int j = 1;j <= m;++j)
                {
                    addflow(i,n+j,lowf[i][j],upf[i][j],++tot);
                }
            }
    

     加边完成后,转化为无源汇有上下界可行流 ———— 循环流

    add(t,s,inf,0);
            int sum = 0;
            for(int i = s;i <= t;++i)
            {
                if(upflow[i] < 0)
                {
                    add(i,tt,-upflow[i],0);
                }
                else
                {
                    sum += upflow[i];
                    add(ss,i,upflow[i],0);
                }
            }
    

     跑DIinc,如果存在可行流的话

    就输出叭~~

    for(int now = n+1;now <= n + m;++now)
                {
                    for(int i = id[now];~i;i = e[i].pre)
                    {
                        int to = e[i].to;
                        int lid = e[i].lid;
                        if(lid == 0 || i % 2 == 0)continue;
                        out[to][now-n] = lowf[to][now-n] + e[i].val;
                    }
                }
                for(int i = 1;i <= n;++i)
                {
                    for(int j = 1;j <= m;++j)
                    {
                        if(j == 1)
                            printf("%d",out[i][j]);
                        else
                            printf(" %d",out[i][j]);
                    }
                    printf("
    ");
                }
    

     完整代码

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #include <queue>
    #define inf (1 << 28)
    using namespace std;
    const int maxn = 25;
    const int maxm = 210;
    const int mn = 505;
    const int mm = 440020;
    struct node{
        int to,val,pre,lid;
    }e[mm];
    int id[mn],cnt=0;
    
    int cur[mn];
    int flor[mn];
    
    int upflow[mn];
    int lowf[maxm][maxn];
    int upf[maxm][maxn];
    int out[maxm][maxn];
    void init()
    {
        memset(id,-1,sizeof(id));
        memset(upflow,0,sizeof(upflow));
        cnt = 0;
    }
    void add(int from,int to,int val,int lid)
    {
        e[cnt].to = to;
        e[cnt].val = val;
        e[cnt].lid = lid;
        e[cnt].pre = id[from];
        id[from] = cnt++;
        swap(from,to);
        e[cnt].to = to;
        e[cnt].val = 0;
        e[cnt].lid = lid;
        e[cnt].pre = id[from];
        id[from] = cnt++;
    }
    void addflow(int from,int to,int low,int up,int lid)
    {
        upflow[from] -= low;
        upflow[to] += low;
        add(from,to,up-low,lid);
    }
    bool bfs(int s,int t)
    {
        memset(flor,0,sizeof(flor));
        flor[s] = 1;
        queue<int> q;
        while(q.size())q.pop();
    
        q.push(s);
        while(q.size())
        {
            int now = q.front();
            q.pop();
    
            for(int i = id[now];~i;i = e[i].pre)
            {
                int to = e[i].to;
                int val = e[i].val;
                if(val > 0 && flor[to] == 0)
                {
                    flor[to] = flor[now] + 1;
                    q.push(to);
                    if(to == t)
                        return true;
                }
            }
        }
        return false;
    }
    int dfs(int s,int t,int value)
    {
        if(s == t || value == 0)return value;
    
        int ret = value,a;
    
        for(int &i = cur[s];~i;i = e[i].pre)
        {
            int val = e[i].val;
            int to = e[i].to;
            if(flor[to] == flor[s] + 1 && (a = dfs(to,t,min(ret,val))))
            {
                e[i].val -= a;
                e[i^1].val += a;
                ret -= a;
                if(ret == 0)break;
            }
        }
        if(ret == value)flor[s] = 0;
        return value - ret;
    }
    
    int Dinic(int s,int t)
    {
        int ret = 0;
        while(bfs(s,t))
        {
            memcpy(cur,id,sizeof(id));
            ret += dfs(s,t,inf);
        }
        return ret;
    }
    
    void addlimit(int i,int j,char op,int lim)
    {
        if(op == '=')
        {
            upf[i][j] = lowf[i][j] = lim;
        }
        else if(op == '>')
        {
            lowf[i][j] = max(lowf[i][j],lim+1);
        }
        else
        {
            upf[i][j] = min(upf[i][j],lim-1);
        }
    }
    int main()
    {
        int T;
        scanf("%d",&T);
        int n,m,s,t,ss,tt;
        while(T--)
        {
            init();
            scanf("%d%d",&n,&m);
            s = 0;
            t = n + m + 1;
            ss = t + 1;
            tt = ss + 1;
            int lsum;
            for(int i = 1;i <= n;++i)
            {
                scanf("%d",&lsum);
                addflow(s,i,lsum,lsum,0);
            }
            for(int i = 1;i <= m;++i)
            {
                scanf("%d",&lsum);
                addflow(n + i,t,lsum,lsum,0);
            }
            int limitnum;
            scanf("%d",&limitnum);
            for(int i = 1;i <= n;++i)
            {
                for(int j = 1;j <= m;++j)
                {
                    lowf[i][j] = 0;
                    upf[i][j] = inf;
                }
            }
            int row,col,lim;
            char op;
            for(int i = 1;i <= limitnum;++i)
            {
                scanf("%d %d %c %d",&row,&col,&op,&lim);
                if(row == 0 && col == 0)
                {
                    for(int i = 1;i <= n;++i)
                    {
                        for(int j = 1;j <= m;++j)
                        {
                            addlimit(i,j,op,lim);
                        }
                    }
                }
                else if(row == 0)
                {
                    for(int i = 1;i <= n;++i)
                    {
                        addlimit(i,col,op,lim);
                    }
                }
                else if(col == 0)
                {
                    for(int i = 1;i <= m;++i)
                    {
                        addlimit(row,i,op,lim);
                    }
                }
                else
                {
                    addlimit(row,col,op,lim);
    
                }
            }
            int tot = 0;
            for(int i = 1;i <= n;++i)
            {
                for(int j = 1;j <= m;++j)
                {
                    addflow(i,n+j,lowf[i][j],upf[i][j],++tot);
                }
            }
            add(t,s,inf,0);
            int sum = 0;
            for(int i = s;i <= t;++i)
            {
                if(upflow[i] < 0)
                {
                    add(i,tt,-upflow[i],0);
                }
                else
                {
                    sum += upflow[i];
                    add(ss,i,upflow[i],0);
                }
            }
            if(Dinic(ss,tt) == sum)
            {
                for(int now = n+1;now <= n + m;++now)
                {
                    for(int i = id[now];~i;i = e[i].pre)
                    {
                        int to = e[i].to;
                        int lid = e[i].lid;
                        if(lid == 0 || i % 2 == 0)continue;
                        out[to][now-n] = lowf[to][now-n] + e[i].val;
                    }
                }
                for(int i = 1;i <= n;++i)
                {
                    for(int j = 1;j <= m;++j)
                    {
                        if(j == 1)
                            printf("%d",out[i][j]);
                        else
                            printf(" %d",out[i][j]);
                    }
                    printf("
    ");
                }
            }
            else
            {
                printf("IMPOSSIBLE
    ");
            }
            if(T)printf("
    ");
        }
        return 0;
    }
    
  • 相关阅读:
    智能推荐算法演变及学习笔记(三):CTR预估模型综述
    从中国农业银行“雅典娜杯”数据挖掘大赛看金融行业数据分析与建模方法
    智能推荐算法演变及学习笔记(二):基于图模型的智能推荐(含知识图谱/图神经网络)
    (设计模式专题3)模板方法模式
    (设计模式专题2)策略模式
    (设计模式专题1)为什么要使用设计模式?
    关于macOS上常用操作命令(持续更新)
    记录下关于RabbitMQ常用知识点(持续更新)
    EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY'RE NOT. RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUST TO BE SAFE.
    SpringCloud教程二:Ribbon(Finchley版)
  • 原文地址:https://www.cnblogs.com/DF-yimeng/p/9740863.html
Copyright © 2011-2022 走看看