ZOJ1994有源匯上下界可行流

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

Description:ios

  n 行 m 列數組

  給你行和 與 列和函數

  而後有Q個限制,表示特定單元格元素大小的範圍,最後問你可行的矩陣值spa

Solution:
  有源匯上下界最大流問題,初始源點 連 行和流量是該行對應得行和,而後列連初始匯點,容量爲列的列和,詳細的限制,對應於行列之間,由於我最後要輸出一個矩陣,因此n * m每一條邊都要連接最後,手動連一條 t s inf的邊,變成無源匯有上下界可行流問題,而後拆邊,把對應邊的流量,放到數組裏,輸出就好啦blog

Code:ip

  前面比較基礎的Dinic,數據操做函數,加邊操做string

#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);
    }
}

 而後根據輸入一點點的加邊,這是行和和列和對應的邊it

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;

 而後根據題目中給出的限制條件,填充上下界數組io

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("\n");
            }

 完整代碼

#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("\n");
            }
        }
        else
        {
            printf("IMPOSSIBLE\n");
        }
        if(T)printf("\n");
    }
    return 0;
}
相關文章
相關標籤/搜索