poj2396有源汇上下界可行流

题意:给一些约束条件,要求算能否有可行流,ps:刚开始输入的是每一列和,那么就建一条上下界相同的边,这样满流的时候就一定能保证流量相同了,还有0是该列(行)对另一行每个点都要满足约束条件

解法:先按无源汇上下界可行流建边,然后添加一条从t到s的容量为inf的边,从超级源到超级汇跑一边最大流,看流量是不是等于新加边的流量和,注意这题有可能输入的数据会有锚段,那么我们需要特判一下是否有矛盾出现

还要注意的一点是:我刚开始是用string+cin读入的字符,但是出现了问题,导致我代码下面的那组数据不能运行,改成scanf却能运行了,为什么单个字符就不能用string读入呢,还是说有其他的格式问题?

#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
#include<cstdio>
#include<cassert>
#include<iomanip>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define pii pair<int,int>
#define C 0.5772156649
#define pi acos(-1.0)
#define ll long long
#define mod 1000000007
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1

using namespace std;

const double g=10.0,eps=1e-12;
const int N=1000+10,maxn=160000+10,inf=0x3f3f3f3f;

struct edge{
    int from,to,Next,c,low;
}e[maxn<<2];
int cnt,head[N];
int in[N],out[N];
int dis[N];
int minn[N][N],maxx[N][N];
void add(int u,int v,int c,int low)
{
  //  cout<<u<<" "<<v<<" "<<c<<" "<<low<<endl;
    out[u]+=low;
    in[v]+=low;
    e[cnt].from=u;
    e[cnt].to=v;
    e[cnt].c=c;
    e[cnt].low=low;
    e[cnt].Next=head[u];
    head[u]=cnt++;
    e[cnt].from=v;
    e[cnt].to=u;
    e[cnt].c=0;
    e[cnt].low=low;
    e[cnt].Next=head[v];
    head[v]=cnt++;
}
void init(int n,int m)
{
    cnt=0;
    memset(head,-1,sizeof head);
    memset(in,0,sizeof in);
    memset(out,0,sizeof out);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            minn[i][j]=0,maxx[i][j]=inf;
}
bool bfs(int s,int t)
{
    memset(dis,-1,sizeof dis);
    dis[s]=0;
    queue<int>q;
    q.push(s);
    while(!q.empty())
    {
        int x=q.front();
        q.pop();
        if(x==t)return 1;
        for(int i=head[x];~i;i=e[i].Next)
        {
            int te=e[i].to;
            if(dis[te]==-1&&e[i].c>0)
            {
                dis[te]=dis[x]+1;
                q.push(te);
            }
        }
    }
    return 0;
}
int dfs(int x,int mx,int t)
{
    if(x==t)return mx;
    int flow=0;
    for(int i=head[x];~i;i=e[i].Next)
    {
        int te=e[i].to,f;
        if(dis[te]==dis[x]+1&&e[i].c>0&&(f=dfs(te,min(mx-flow,e[i].c),t)))
        {
            e[i].c-=f;
            e[i^1].c+=f;
            flow+=f;
        }
    }
    if(!flow)dis[x]=-2;
    return flow;
}
int maxflow(int s,int t)
{
    int ans=0,f;
    while(bfs(s,t))
    {
        while((f=dfs(s,inf,t)))ans+=f;
    }
    return ans;
}
int main()
{
   /* ios::sync_with_stdio(false);
    cin.tie(0);*/
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n,m;
        scanf("%d%d",&n,&m);
        init(n,m);
        int s=n+m+1,t=n+m+2,sum1=0,sum2=0;
        bool can=1;
        for(int i=1;i<=n;i++)
        {
            int a;
            scanf("%d",&a);
            sum1+=a;
            add(s,i,0,a);
            if(a<0)can=0;
        }
        for(int i=1;i<=m;i++)
        {
            int a;
            scanf("%d",&a);
            sum2+=a;
            add(i+n,t,0,a);
            if(a<0)can=0;
        }
        int res;
        scanf("%d",&res);
        while(res--)
        {
            int a,b,c;char str;
            scanf("%d %d %c %d",&a,&b,&str,&c);
            if(str==‘<‘&&c<0)can=0;
            if(str==‘=‘)
            {
                if(a==0&&b==0)
                {
                    for(int i=1;i<=n;i++)
                        for(int j=1;j<=m;j++)
                        {
                            minn[i][j]=max(minn[i][j],c);
                            maxx[i][j]=min(maxx[i][j],c);
                        }
                }
                else if(a!=0&&b==0)
                {
                    for(int j=1;j<=m;j++)
                    {
                        minn[a][j]=max(minn[a][j],c);
                        maxx[a][j]=min(maxx[a][j],c);
                    }
                }
                else if(a==0&&b!=0)
                {
                    for(int i=1;i<=n;i++)
                    {
                        minn[i][b]=max(minn[i][b],c);
                        maxx[i][b]=min(maxx[i][b],c);
                    }
                }
                else if(a!=0&&b!=0)
                {
                    minn[a][b]=max(minn[a][b],c);
                    maxx[a][b]=min(maxx[a][b],c);
                }
            }
            else if(str==‘>‘)
            {
                if(a==0&&b==0)
                {
                    for(int i=1;i<=n;i++)
                        for(int j=1;j<=m;j++)
                        {
                            minn[i][j]=max(minn[i][j],c+1);
                        }
                }
                else if(a!=0&&b==0)
                {
                    for(int j=1;j<=m;j++)
                    {
                        minn[a][j]=max(minn[a][j],c+1);
                    }
                }
                else if(a==0&&b!=0)
                {
                    for(int i=1;i<=n;i++)
                    {
                        minn[i][b]=max(minn[i][b],c+1);
                    }
                }
                else if(a!=0&&b!=0)
                {
                    minn[a][b]=max(minn[a][b],c+1);
                }
            }
            else
            {
                if(a==0&&b==0)
                {
                    for(int i=1;i<=n;i++)
                        for(int j=1;j<=m;j++)
                        {
                            maxx[i][j]=min(maxx[i][j],c-1);
                        }
                }
                else if(a!=0&&b==0)
                {
                    for(int j=1;j<=m;j++)
                    {
                        maxx[a][j]=min(maxx[a][j],c-1);
                    }
                }
                else if(a==0&&b!=0)
                {
                    for(int i=1;i<=n;i++)
                    {
                        maxx[i][b]=min(maxx[i][b],c-1);
                    }
                }
                else if(a!=0&&b!=0)
                {
                    maxx[a][b]=min(maxx[a][b],c-1);
                }
            }
        }
        int be=cnt;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
            //    cout<<maxx[i][j]<<" "<<minn[i][j]<<endl;
                if(maxx[i][j]<minn[i][j])can=0;
                add(i,j+n,maxx[i][j]-minn[i][j],minn[i][j]);
            }
        }
        int en=cnt-1;
        add(t,s,inf,0);
        int ss=n+m+3,tt=n+m+4,sum3=0;
        for(int i=1;i<=n+m+2;i++)
        {
            if(in[i]>out[i])add(ss,i,in[i]-out[i],0),sum3+=in[i]-out[i];
            else add(i,tt,out[i]-in[i],0);
        }
        if(sum1!=sum2||!can||sum3!=maxflow(ss,tt))puts("IMPOSSIBLE");
        else
        {
            can=1;
            for(int i=be;i<=en;i+=2)
            {
                if(e[i^1].c+e[i].low<0)
                {
                    can=0;
                    break;
                }
            }
            if(can==0)puts("IMPOSSIBLE");
            else
            {
                int co=0;
                for(int i=be;i<=en;i+=2)
                {
                    printf("%d",e[i^1].c+e[i].low);
                    co++;
                    if(co!=m)printf("%c",‘ ‘);
                    else puts(""),co=0;
                }
            }
        }
        puts("");
    }
    return 0;
}
/********************
179 20
10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000 10000
89500 89500 89500 89500 89500 89500 89500 89500 89500 89500 89500 89500 89500 89500 89500 89500 89500 89500 89500 89500
5
130 0 > 307
0 0 < 366
0 0 > 329
0 0 < 341
0 0 < 324
********************/

时间: 2024-11-05 16:41:54

poj2396有源汇上下界可行流的相关文章

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

链接:http://poj.org/problem?id=2396 题意:给一个n*m的矩阵,给出每行的总和以及每列的总和,再给出某些位置的最小或最大限制,问是否存在可能的矩阵,如果存在输出一种矩阵信息. 思路:这是一个有源汇的上下界可行流,对于这种题,从汇点连一条弧到源点,容量为INF,这不会影响流量平衡条件,并且此时原图转换为了无源汇的上下界可行流,剩下的做法和无源汇一样. 建图:原图源点src连向每个行顶点,容量为每行的和,每个列顶点连向汇点,容量为每个列顶点的和,行顶点和列顶点间也各有一

有源汇上下界可行流(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,

算法复习——有源汇上下界可行流(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的边

poj2396 Budget 有源汇上下界可行流

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

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