加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

POJ PKU 2396 上下界最大流

(2010-08-26 21:36:49)
标签:

poj

pku

2396

上下界最大流

杂谈

分类: 网络流

题目描述:

一个n*m的矩阵

告诉你每一行元素的和。n个

每一列元素的和。m个

然后有t个条件:

每一个条件

a b c d 四个参数。

表示 元素 a b 和数字 d 满足条件 c;

例如:

2 1 = 3

2行1列的元素等于3

2 3 < 5

2行3列的元素小于5

0 2 > 2

(0表示所有)

表示所有行(1到n)的2列元素都要大于2.

问你:能不能找到满足所有条件的n*m的矩阵。

如果能的话,任意输出一个(题目是SPJ)

解题报告:

上下界的最大流就是每条边的流量有一个不能超过的上界(我们平时说的容量),还有一个不能低于的下界。

在这种情况下求出一个最大流。

1到n行:每行是一个节点

1到m列:每列是一个节点

源点s和每一个行节点连接,上界是行数字的和。下界0

每一个列节点和汇点t连接,上界是列数字的和,下界0

如果i行j列的数字大于x

那么i行节点连接j列节点,上界无穷,下界为x+1

如果i行j列的数字小于x

那么i行节点连接j列节点,上界为x - 1,下界为0

等于的话,上下界都是x。

这样建图,i行与j列的流量就是i,j的值,很好理解。

如果最大流等于所有行元素的和,就存在解,输出流量即可。

代码如下:

#include<iostream>
using namespace std;
#define Max 0x7fffffff
#define MAXN 300
#define inf 1000000000
void maxflow(int n, int src, int sink, int up[][MAXN], int flow[][MAXN])
{
    int pv[MAXN], que[MAXN], d[MAXN];
    int p, q, t, i, j;
    do
    {
        for (i = 0; i < n; pv[i++] = 0) ;
        pv[t = src] = src + 1; d[t] = inf;
        for (p=q=0; p<=q && !pv[sink]; t=que[p++])
            for (i=0; i<n; i++)
            {
                if(!pv[i]&&up[t][i]&&(j=up[t][i]-flow[t][i])>0)
                    pv[que[q++]=i]=+t+1, d[i]=d[t]<j?d[t]:j;
                else if (!pv[i]&&up[i][t]&&(j=flow[i][t])>0)
                    pv[que[q++]=i]=-t-1, d[i]=d[t]<j?d[t]:j;
            }
        for (i=sink; pv[i] && i!=src; )
        {
            if(pv[i]>0)flow[pv[i]-1][i]+=d[sink],i=pv[i]-1;
            else flow[i][-pv[i]-1]-=d[sink], i=-pv[i]-1;
        }
    }while (pv[sink]);
}
int limitflow(int n, int src, int sink, int up[][MAXN], int low[][MAXN], int flow[][MAXN])
{
    int i, j, sk, ks;
    if (src == sink) return inf;
    up[n][n+1] = up[n+1][n] = up[n][n] = up[n+1][n+1] = 0;
    for (i = 0; i < n; i++)
    {
        up[n][i] = up[i][n] = up[n+1][i] = up[i][n+1] = 0;
        for (j = 0; j < n; j++)
        {
            up[i][j] -= low[i][j];
            up[n][i] += low[j][i];
            up[i][n+1] += low[i][j];
        }
    }
    sk = up[src][sink]; ks = up[sink][src];
    up[src][sink] = up[sink][src] = inf;
    maxflow(n+2, n, n+1, up, flow);
    for (i = 0; i < n; i++)
        if (flow[n][i] < up[n][i]) return -1;
    flow[src][sink] = flow[sink][src] = 0;
    up[src][sink] = sk; up[sink][src] = ks;
    maxflow(n, src, sink, up, flow);
    for (i = 0; i < n; i++) for (j = 0; j < n; j++)
    {
        up[i][j] += low[i][j];
        flow[i][j] += low[i][j];
    }
    for (j = i = 0; i < n; j += flow[src][i++]);
    return j;
}
int tt, n, m;
int cap[MAXN][MAXN], buf[MAXN][MAXN], ans[MAXN][MAXN];
int main()
{
    scanf("%d", &tt);
    bool jeo = false;
    while(tt--)
    {
        scanf("%d%d", &n, &m);
        int s = 0, t = n + m + 1, sum1 = 0, sum2 = 0;;
        memset(cap, 0, sizeof(cap)); memset(buf, 0, sizeof(buf));
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= m; j++) cap[i][j + n] = inf;

        for(int i = 1; i <= n; i++) scanf("%d", &cap[s][i]), sum1 += cap[s][i];
        for(int i = n + 1; i <= n + m; i++) scanf("%d", &cap[i][t]), sum2 += cap[i][t];
        int ttt; scanf("%d", &ttt);
        bool flag = true;
        while(ttt--)
        {
            int a, b, d; char c[2];
            scanf("%d%d%s%d", &a, &b, c, &d);
            int from1, to1, from2, to2; from1 = to1 = a; from2 = to2 = b;
            if (a == 0) from1 = 1, to1 = n;
            if (b == 0) from2 = 1, to2 = m;
            for(int i = from1; i <= to1; i++)
                for(int j = from2; j <= to2; j++)
                {
                    if (c[0] == '=')
                    {
                        cap[i][j + n] = buf[i][j + n] = d;
                        if (d > cap[s][i] || d > cap[j + n][t]) flag = false;
                    }
                    else if (c[0] == '>' && d + 1 > buf[i][j + n])
                    {
                        buf[i][j + n] = d + 1;
                        if (d + 1 > cap[s][i] || d + 1 > cap[j + n][t]) flag = false;
                    }
                    else if (c[0] == '<' && d - 1 < cap[i][j + n])
                        cap[i][j + n] = d - 1;
                }
        }
       
        if (jeo) putchar('\n');
        else jeo = true;
        if (sum1 == sum2 && flag)
        {
            memset(ans, 0, sizeof(ans));
            int tmp = limitflow(t + 1, s, t, cap, buf, ans);
            //cout << tmp << endl;
            if (tmp != -1 && tmp == sum1)
            {
                for(int i = 1; i <= n; i++)
                {
                    printf("%d", ans[i][1 + n]);
                    for(int j = 2; j <= m; j++)
                        printf(" %d", ans[i][j + n]);
                    putchar('\n');
                }
            }
            else printf("IMPOSSIBLE\n");
        }
        else printf("IMPOSSIBLE\n");
    }
    return 0;
}

 

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有