poj2396有上下限网络流

poj2396有上下限网络流

链接:http://poj.org/problem?id=2396

题目部分

我直接介绍下数据是什么的,前面题意就不用讲了没什么用。
先说这题想要我们求出一个矩阵,会告诉我们这个矩阵有几行几列,每一行的和,每一列的和,还有行和列之间的约束关系。
第一个数字是告诉你有几个测试数据
每组测试数据第一行的2个数字是这个矩阵有几行m几列n
第2行的数据是这个矩阵每一行的和
第3行的数据是这个矩阵每一列的和
第4行的数据c是这个矩阵有几个约束条件
接下来c行数据就是介绍约束了。
我这里用a,b,cha,v来表示4个输入的东西,a代表第a行,b代表第b列,cha只有三种可能(<, = , >),<代表a行b列的值要小于v,>代表a行b列的值要大于v,=代表a行b列的值要等于v。(如果a或b的值等于0就说明所有的列或所有的行要满足这个约束,如0 2 > 2代表所有的第二列都满足值大于2,如果是0 0 就代表所有的数都满足这个条件)
这里有个坑,每行每列有可能有多个约束,下限要取最大的,上限要取最小的。
题目要我们给出结果,如果存在这个矩阵就输出这个矩阵,如果不存在就输出impossible
像这组测试数据
2 3
8 10
5 6 7
4
0 2 > 2
2 1 = 3
2 3 > 2
2 3 < 5
就是说有2行3列,第一行的和是8,第二行的和是10,第一列的和是5,第2列的和是6,第三列的和是7,有4个约束,第一个约束是第2列上的所有元素都大于2,第二个约束是第二行第一列的元素等于3,第三个约束是第二行第三列上的元素大于2,第四个约束是第二行第三列小于5。求这个矩阵。

思路部分

先给出别人找到的测试数据:
http://www.ida.liu.se/projects/progcontest/progsm/2003/problems/budget.in
网络流嘛,将每一行每一列当成一个点,行与列之间的关系就变成点与点之间的连线,约束就成为了上下限,行和就相当于源点出发的代表行的点的连线约束,列和就相当于代表列的点到汇点的连线约束,这样就变成了一个有上下限的网络流了。

╮(╯▽╰)╭,上下限的网络流该怎么做呢?我是不会讲解的人,就只要记得是怎么做的就好了。
设置额外的两个点x,y,把所有下限拆分出来,map上的值就为上限减下限的和(也就变成正常的网络流图了)。
下限拆成2段,一段变成边起点流向x,另外一段变成y流向边终点,这两条边的值为下限的值,要算所有下限的总和,因为如果改的图算出来的最大流不等于下限总和,就说明这个网络流无解。
再在源点与汇点加一条边,由汇点流向源点,边的值为无限(inf)。
把改好的图扔到Dinic里面跑得到最大流,得到最大流,然后在把x,y去掉,汇点流向源点的边去掉,再用去掉后的图扔到Dinic里面跑,得到最大流,两个相加就是有上下限的网络流的最大流。
至于这题要的矩阵就是做完Dinic后的map[j][i]+down[i][j](反向边加下限)

代码部分

这题卡了1个星期~~(>_<)~~,主要还是没看清楚上下限的网络流该怎么建,漏掉了源点与汇点有关的必须边,边的方向还建反了╮(╯▽╰)╭。
来贴个代码。判断impossible的时候记得有一点,总行和要是不等于总列和就可以说impossible,毕竟所有的行和就是这个矩阵的所有元素的和,要是不等于所有列和,那么这个矩阵就不可能存在。
举个例子
2 2
4 5
6 7
0
这个矩阵肯定不存在。4+5 != 6+ 7

#include<iostream>
#include<cstring>
#include<algorithm>
#include<fstream>
#include<math.h>
#include<algorithm>
#include<stack>
#include<queue>
using namespace std;
fstream fin("1.txt");
//streambuf *buf = cin.rdbuf(fin.rdbuf());//用于重定项输入改成,把cin当成fin


const int inf = 1 << 29;
const int MAXN = 310;


int n, m, c;//m为行,n为列,c为约束个数
int s, t;//s为源点,t为汇点
int down[MAXN][MAXN];//下限
int up[MAXN][MAXN];
int map[MAXN][MAXN];
int xin[MAXN];
int yout[MAXN];
int layer[MAXN];
bool vis[MAXN];

bool init()
{
    cin >> m >> n;
    s = n + m + 1;
    t = s + 1;
    for (int i = 0; i <= t; i++)
    {
        for (int j = 0; j <= t; j++)
        {
            map[i][j] = 0;
            down[i][j] = 0;
            up[i][j] = 0;
        }
    }
    int value, first, second;
    char cha;
    int rsum = 0, csum = 0;
    for (int i = 1; i <= m; i++)
    {
        cin >> value;
        down[s][i] = value;
        up[s][i] = value;
        rsum += value;
    }
    for (int i = m + 1; i < s; i++)
    {
        cin >> value;
        down[i][t] = value;
        up[i][t] = value;
        csum += value;
    }
    for (int i = 1; i <= m; i++)
    {
        for (int j = m + 1; j < s; j++)
        {
            up[i][j] = inf;
            down[i][j] = 0;
        }
    }
    cin >> c;
    for (int i = 0; i < c; i++)
    {
        cin >> first >> second;
        cin >> cha;
        cin >> value;
        if (first == 0 && second == 0)//所有的行与列都要满足这个约束
        {
            if (cha == '=')//等号,上下界相同
            {
                for (int i = 1; i <= m; i++)
                {
                    for (int j = m + 1; j < s; j++)
                    {
                        up[i][j] = value;
                        down[i][j] = value;
                    }
                }
            }
            else if (cha == '>')//下限
            {
                value = value + 1;
                for (int i = 1; i <= m; i++)
                {
                    for (int j = m + 1; j < s; j++)
                    {
                        down[i][j] = max(value, down[i][j]);
                    }
                }
            }
            else //上限
            {
                value = value - 1;
                for (int i = 1; i <= m; i++)
                {
                    for (int j = m + 1; j < s; j++)
                    {
                        up[i][j] = min(value, up[i][j]);
                    }
                }
            }
        }
        if (first == 0 && second != 0)//second列所有的都要满足这个约束
        {
            int col = second + m;
            if (cha == '=')//等号,上下界相同
            {
                for (int i = 1; i <= m; i++)
                {
                    up[i][col] = value;
                    down[i][col] = value;
                }
            }
            else if (cha == '>')//下限
            {
                value = value + 1;
                for (int i = 1; i <= m; i++)
                {
                    down[i][col] = max(value, down[i][col]);
                }
            }
            else //上限
            {
                value = value - 1;
                for (int i = 1; i <= m; i++)
                {
                    up[i][col] = min(value, up[i][col]);
                }
            }
        }
        if (first != 0 && second == 0)//first所有的行都要满足这个约束
        {
            if (cha == '=')//等号,上下界相同
            {
                for (int i = m + 1; i < s; i++)
                {
                    up[first][i] = value;
                    down[first][i] = value;
                }
            }
            else if (cha == '>')//下限
            {
                value = value + 1;
                for (int i = m + 1; i < s; i++)
                {
                    down[first][i] = max(value, down[first][i]);
                }
            }
            else //上限
            {
                value = value - 1;
                for (int i = m + 1; i < s; i++)
                {
                    up[first][i] = min(value, up[first][i]);
                }
            }
        }
        if (first != 0 && second != 0)//first行,second列要满足约束
        {
            int col = m + second;
            if (cha == '=')//等号,上下界相同
            {
                up[first][col] = value;
                down[first][col] = value;
            }
            else if (cha == '>')//下限
            {
                value = value + 1;
                down[first][col] = max(value, down[first][col]);
            }
            else //上限
            {
                value = value - 1;
                up[first][col] = min(value, up[first][col]);
            }
        }
    }
    if (rsum != csum)
    {
        return false;
    }
    return true;
}
bool bfs_getlayer(int ss, int tt, int nn)
{
    int temp;
    queue<int> que;
    for (int i = 0; i <= nn; i++)
    {
        layer[i] = -1;
    }
    que.push(ss);
    layer[ss] = 0;
    while (!que.empty())
    {
        temp = que.front();
        que.pop();
        for (int i = 1; i <= nn; i++)
        {
            if (map[temp][i] && layer[i] == -1)
            {
                layer[i] = layer[temp] + 1;
                if (i == tt)
                    return true;
                else
                    que.push(i);
            }
        }
    }
    return false;
}
int Dinic(int ss, int tt, int nn)//s源点,t汇点,nn点个数
{
    int Maxflow = 0;
    int minc;//最小容量
    int mins;//最小容量边起点
    int temp;
    deque<int> sta;
    while (bfs_getlayer(ss, tt, nn))
    {
        sta.push_back(ss);
        for (int i = 0; i <= nn; i++)
        {
            vis[i] = false;
        }
        vis[ss] = true;
        while (!sta.empty())
        {
            temp = sta.back();
            if (temp == tt)
            {
                minc = inf;
                for (int i = 1; i < sta.size(); i++)
                {
                    int ts = sta[i - 1];
                    int te = sta[i];
                    if (minc > map[ts][te])
                    {
                        minc = map[ts][te];
                        mins = ts;
                    }
                }
                Maxflow += minc;
                for (int i = 1; i < sta.size(); i++)
                {
                    int ts = sta[i - 1];
                    int te = sta[i];
                    map[ts][te] -= minc;
                    map[te][ts] += minc;
                }
                //退栈
                while (!sta.empty() && sta.back() != mins)
                {
                    vis[sta.back()] = false;
                    sta.pop_back();
                }
            }
            else
            {
                int i;
                for (i = 1; i <= nn; i++)
                {
                    if (map[temp][i] && layer[i] == layer[temp] + 1 && !vis[i])
                    {
                        vis[i] = true;
                        sta.push_back(i);
                        break;
                    }
                }
                if (i > nn)
                    sta.pop_back();
            }
        }
    }
    return Maxflow;
}
void solve()
{
    int x = t + 1, y = x + 1;
    int sum = 0;
    memset(xin, 0, sizeof(xin));
    memset(yout, 0, sizeof(yout));
    memset(map, 0, sizeof(map));
    for (int i = 1; i <= t; i++)
    {
        for (int j = 1; j <= t; j++)
        {
            map[i][j] = up[i][j] - down[i][j];
            xin[i] += down[i][j];
            yout[j] += down[i][j];
            sum += down[i][j];
        }
    }
    for (int i = 1; i <= t; i++)
    {
        map[i][x] = xin[i];
        map[y][i] = yout[i];
    }
    map[t][s] = inf;
    for (int i = 1; i <= m; i++)
    {
        for (int j = m + 1; j < s; j++)
        {
            map[i][j] = up[i][j] - down[i][j];
        }
    }
    int result = Dinic(y, x, t + 2);
    if (sum != result)
    {
        cout << "IMPOSSIBLE" << endl << endl;
        return;
    }
    //到这里说明必须边都满足,存在最大流
    map[t][s] = 0;
    map[s][t] = 0;
    result = Dinic(s, t, t);
    for (int i = 1; i <= m; i++)
    {
        for (int j = 1; j <= n; j++)
        {
            cout << (map[j + m][i] + down[i][j + m]) << " ";
        }
        cout << endl;
    }
    cout << endl;
}
int main()
{
    int test;
    cin >> test;
    while (test--)
    {
        if(init())
            solve();
        else
            cout << "IMPOSSIBLE" << endl << endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值