POJ2396&ZOJ1994--Budget【有源汇上下界可行流】

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

题意:给一个n*m的矩阵,给出每行的总和以及每列的总和,再给出某些位置的最小或最大限制,问是否存在可能的矩阵,如果存在输出一种矩阵信息。

思路:这是一个有源汇的上下界可行流,对于这种题,从汇点连一条弧到源点,容量为INF,这不会影响流量平衡条件,并且此时原图转换为了无源汇的上下界可行流,剩下的做法和无源汇一样。

建图:原图源点src连向每个行顶点,容量为每行的和,每个列顶点连向汇点,容量为每个列顶点的和,行顶点和列顶点间也各有一条弧,初始容量无下界、无上界,输入时再更新。最后连一条汇点指向源点的容量为INF的弧,剩下就是无源汇的做法。

这道题细节还是挺多的,初始化挫了WA出了翔。还有我在POJ上C++交TLE了,去ZOJ上交却过了,再回POJ用G++交才AC,不明觉厉。

isap代码

#include<cstring>
#include<string>
#include<fstream>
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cctype>
#include<algorithm>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<stack>
#include<ctime>
#include<cstdlib>
#include<functional>
#include<cmath>
using namespace std;
#define PI acos(-1.0)
#define MAXN 100100
#define eps 1e-7
#define INF 0x7FFFFFFF
#define seed 131
#define ll long long
#define ull unsigned ll
#define lson l,m,rt<<1
#define rson r,m+1,rt<<1|1

struct node{
    int u,v,w,next;
}edge[20000];
int head[250],dist[250],cur[250],fa[250],num[250];
int low[300][300],upp[300][300],D[250];
int n,m,cnt,nn,src,sink,supersrc,supersink;

void add_edge(int a,int b,int c){
    edge[cnt].u = a;
    edge[cnt].v = b;
    edge[cnt].w = c;
    edge[cnt].next = head[a];
    head[a] = cnt++;
}
void build_graph(){
    int i,j;
    for(i=1;i<=n;i++){
        for(j=n+1;j<=n+m;j++){
            D[i] -= low[i][j];
            D[j] += low[i][j];
            add_edge(i,j,upp[i][j]-low[i][j]);
            add_edge(j,i,0);
        }
    }
    add_edge(sink,src,INF);
    add_edge(src,sink,0);
    for(i=0;i<=n+m+1;i++){
        if(D[i]==0) continue;
        else if(D[i]>0){
            add_edge(supersrc,i,D[i]);
            add_edge(i,supersrc,0);
        }
        else{
            add_edge(i,supersink,-D[i]);
            add_edge(supersink,i,0);
        }
    }
}
void bfs()
{
    int x,i,j;
    queue<int> q;
    memset(dist,-1,sizeof(dist));
    q.push(supersink);
    dist[supersink] = 0;
    while(!q.empty()){
        x = q.front();
        q.pop();
        for(i=head[x];i!=-1;i=edge[i].next){
            if(dist[edge[i].v]<0){
                dist[edge[i].v] = dist[x] + 1;
                q.push(edge[i].v);
            }
        }
    }
}

int augment()
{
    int x=supersink,a=INF;
    while(x!=supersrc){
        a = min(a,edge[fa[x]].w);
        x = edge[fa[x]].u;
    }
    x=supersink;
    while(x!=supersrc){
        edge[fa[x]].w -= a;
        edge[fa[x]^1].w += a;
        x = edge[fa[x]].u;
    }
    return a;
}

int isap()
{
    int i,x,ok,minm,flow=0;
    memset(num,0,sizeof(num));
    bfs();
    for(i=0;i<=nn+1;i++) num[dist[i]]++;
    for(i=0;i<=nn+1;i++) cur[i] = head[i];
    x=supersrc;
    while(dist[supersrc]<nn){
        if(x==supersink){
            flow += augment();
            x = supersrc;
        }
        ok=0;
        for(i=cur[x];i!=-1;i=edge[i].next){
            if(edge[i].w && dist[x]==dist[edge[i].v]+1){
                ok=1;
                fa[edge[i].v] = i;
                cur[x] = i;
                x = edge[i].v;
                break;
            }
        }
        if(!ok){
            minm = nn - 1;
            for(i=head[x];i!=-1;i=edge[i].next)
                if(edge[i].w && dist[edge[i].v]<minm)   minm=dist[edge[i].v];
            if(--num[dist[x]]==0)break;
            num[dist[x]=minm+1]++;
            cur[x]=head[x];
            if(x!=supersrc)  x=edge[fa[x]].u;
        }
    }
    return flow;
}

int main(){
    int t,q,i,j;
    int a,b,c,d;
    char str[5];
    scanf("%d",&t);
    int cas = 0;
    while(t--){
        if(!cas)    cas = 1;
        else    puts("");
        scanf("%d%d",&n,&m);
        memset(head,-1,sizeof(head));
        memset(D,0,sizeof(D));
        cnt = 0;
        src = 0;
        sink = n + m + 1;
        supersrc = sink + 1;
        supersink = sink + 2;
        nn = sink + 3;
        for(i=0;i<=n+3;i++){
            for(j=n+1;j<=n+m+3;j++){
                low[i][j] = 0;
                upp[i][j] = INF;
            }
        }
        for(i=1;i<=n;i++){
            scanf("%d",&a);
            D[src] -= a;
            D[i] += a;
        }
        for(i=n+1;i<=n+m;i++){
            scanf("%d",&a);
            D[i] -= a;
            D[sink] += a;
        }
        int r1,r2,c1,c2;
        scanf("%d",&q);
        while(q--){
            scanf("%d%d%s%d",&a,&b,str,&c);
            if(a==0){
                r1 = 1;
                r2 = n;
            }
            else    r1 = r2 = a;
            if(b==0){
                c1 = n + 1;
                c2 = n + m;
            }
            else    c1 = c2 = b + n;
            for(i=r1;i<=r2;i++){
                for(j=c1;j<=c2;j++){
                    if(str[0]=='<') upp[i][j] = min(c-1,upp[i][j]);
                    else if(str[0]=='>')    low[i][j] = max(c+1,low[i][j]);
                    else{
                        low[i][j] = max(c,low[i][j]);
                        upp[i][j] = min(c,upp[i][j]);
                    }
                }
            }
        }
        build_graph();
        isap();
        int flag = 0;
        for(i=head[supersrc];i!=-1;i=edge[i].next){
            if(edge[i].w!=0){
                flag = 1;
                break;
            }
        }
        if(flag)    puts("IMPOSSIBLE");
        else{
            for(i=1;i<=n;i++){
                for(j=1;j<m;j++){
                    printf("%d ",edge[(((i-1)*m+j-1)*2)^1].w+low[i][j+n]);
                }
                printf("%d\n",edge[(((i-1)*m+j-1)*2)^1].w+low[i][j+n]);
            }
        }
    }
    return 0;
}

POJ2396&ZOJ1994--Budget【有源汇上下界可行流】

时间: 2024-10-22 13:18:10

POJ2396&ZOJ1994--Budget【有源汇上下界可行流】的相关文章

poj2396 Budget 有源汇上下界可行流

/** 题目:poj2396 Budget 链接:http://poj.org/problem?id=2396 题意: 给定一个n*m矩阵,矩阵元素未知.已知第1~n行的元素和,第1~m列的元素和.以及元素的一些数据范围. 求一个可行的矩阵. 思路: 联想到以前没有下届的做法,用一个s连接所有的行节点,容量为该行的和,所有的列节点连接t,容量为该列的和. 所有的行节点连接所有的列节点,容量为无穷,然后求s到t的最大流.如果从s出发的弧都是满载的,那么有解. 所有行到所有列的flow为对应的行列位

有源汇上下界可行流(POJ2396)

题意:给出一个n*m的矩阵的每行和及每列和,还有一些格子的限制,求一组合法方案. 源点向行,汇点向列,连一条上下界均为和的边. 对于某格的限制,从它所在行向所在列连其上下界的边. 求有源汇上下界可行流即可. 具体做法可以从汇点向源点连容量为正无穷的边,转成无源汇上下界可行流. 然后可以新建超级源汇,对于一条下界为l,上界为r的边(x,y),从超级源点向y,x向超级汇点连容量为l的边,x向y连容量为r-l的边. 如果那些容量为l的边没满流,则无解. #include <cstdio> #incl

poj2396 Budget(有源汇上下界可行流)

[题目链接] http://poj.org/problem?id=2396 [题意] 知道一个矩阵的行列和,且知道一些格子的限制条件,问一个可行的方案. [思路] 设行为X点,列为Y点,构图:连边(s,Xi,sumXi,sumXi)(Yi,t,sumYi,sumYi)(Xi,Yj,down[i][j],up[i][j]). 则问题就是求一个有源汇点st的上下界可行流. 类似于 无源无汇上下界可行流 ,添加附加源汇点ST,边权转化为up-down,由ST向每个点连边保持流量平衡.然后添加(t,s,

poj2396有源汇上下界可行流

题意:给一些约束条件,要求算能否有可行流,ps:刚开始输入的是每一列和,那么就建一条上下界相同的边,这样满流的时候就一定能保证流量相同了,还有0是该列(行)对另一行每个点都要满足约束条件 解法:先按无源汇上下界可行流建边,然后添加一条从t到s的容量为inf的边,从超级源到超级汇跑一边最大流,看流量是不是等于新加边的流量和,注意这题有可能输入的数据会有锚段,那么我们需要特判一下是否有矛盾出现 还要注意的一点是:我刚开始是用string+cin读入的字符,但是出现了问题,导致我代码下面的那组数据不能

算法复习——有源汇上下界可行流(bzoj2396)

题目: Description We are supposed to make a budget proposal for this multi-site competition. The budget proposal is a matrix where the rows represent different kinds of expenses and the columns represent different sites. We had a meeting about this, so

ZOJ1994有源汇上下界可行流

http://fastvj.rainng.com/contest/236779#problem/G Description: n 行 m 列 给你行和 与 列和 然后有Q个限制,表示特定单元格元素大小的范围,最后问你可行的矩阵值 Solution: 有源汇上下界最大流问题,初始源点 连 行和流量是该行对应得行和,然后列连初始汇点,容量为列的列和,详细的限制,对应于行列之间,因为我最后要输出一个矩阵,所以n * m每一条边都要链接最后,手动连一条 t s inf的边,变成无源汇有上下界可行流问题,

bzoj千题计划158:bzoj2406: 矩阵(有源汇上下界可行流)

http://www.lydsy.com/JudgeOnline/problem.php?id=2406 设矩阵C=A-B 最小化 C 一行或一列和的最大值 整体考虑一行或者一列的和 二分最大值 这样每一行一列的和就有了范围 |Σai-Σbj|<=mid 去掉绝对值 Σai-mid <= Σbi <= Σai+mid 构图: 源点向行连下界为Σai-mid,上界为 Σai+mid 的边 列向汇点连下界为Σai-mid,上界为 Σai+mid 的边 第i行向第j列连下界为L,上界为R的边

sgu176 有源汇上下界最小流

题意:有一堆点和边,1起点,n终点,某些边有可能必须满流,要求满足条件的最小流 解法:按原图建边,满流的即上下界都是容量,但是这样按有源汇上下界可行流求出来的可能不是最小流,那么我们需要开始建边的时候不要建从t到s的边,先跑一边从ss到tt的最大流,然后把该边加上再跑一次从ss到tt的最大流,那么从t到s的反向边流过的流量就是原图的最小流,为什么是这样呢,这是因为当我们第一遍跑最大流的时候,此时没有t到s的这条边,那么图中的流量会尽量按其他的边流,当我们第二次跑最大流的时候,流出来的都是第一次中

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

zoj 文文要给幻想乡的女孩子们拍照,一共n天,m个女孩子,每天文文至多拍D[i]张照片,每个女孩子总共要被文文至少拍G[i]次.在第i天,文文可以拍c[i]个女孩子,c[i]个女孩子中每个女孩子在当天被拍的次数是[l,r],求最多可以拍多少张照片,以及每天每个可以拍的女孩子被拍了多少张照片. 有源汇上下界最大流. 先跑有源汇上下界可行流,判断是否可行,若可行则此时跑原图中s到t的最大流即为答案. //代码与题解不符-- #include<cstdio> #include<algorit