ZOJ1994有源汇上下界可行流

Posted df-yimeng

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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;
}

 


以上是关于ZOJ1994有源汇上下界可行流的主要内容,如果未能解决你的问题,请参考以下文章

zoj3229 有源汇上下界最大流

[zoj] 3229 Shoot the Bullet || 有源汇上下界最大流

有上下界的网络流2-有源汇带上下界网络流ZOJ3229

[zoj] 3496 Assignment || 有源汇上下界最大流

zoj 3229 有源汇有上下界的最大流模板题

zoj 3229 Shoot the Bullet(有源汇上下界最大流)