POJ 2396 有源汇上下界判断可行解

点击打开链接

题意:有一个n行m列的数列,每行元素和的值和每列元素和的值给了你,下面有元素取值的限制条件,如0 0 > 1代表的是这个数列的所有元素都大于1,0代表的就是所有,0 1就是所有行的第一个元素,1 0就是第一行,然后判断是数列在满足这些条件的情况下是否有解

思路:给的条件就是给你上界和下界,然后这题是有源汇点的,源点连行,列连汇点,与HDU4975类似hdu 4975,然后就是将有源汇点的变成无源汇的,只需连一条汇点到源点的inf边即可,然后与无源汇的做法一样,建议不会无源汇的先去学习学习,然后判断是否满流来判断有没有解,但是最后我们还要将源点与汇点的边去掉在跑一遍源点到汇点,这是因为之前只是判断有没有解,但是网络里还有可以继续流的可能,跑完后才是将所有和分到所

#include <queue>
#include <vector>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int maxn=260;
struct edge{
    int to,cap,rev;
    edge(){}
    edge(int a,int b,int c){to=a;cap=b;rev=c;}
};
vector<edge> G[maxn];
int level[maxn],iter[maxn],flag;
void add_edge(int from,int to,int cap){
    G[from].push_back(edge(to,cap,G[to].size()));
    G[to].push_back(edge(from,0,G[from].size()-1));
}
void bfs(int s){
    memset(level,-1,sizeof(level));
    queue<int>que;
    level[s]=0;que.push(s);
    while(!que.empty()){
        int v=que.front();que.pop();
        for(unsigned int i=0;i<G[v].size();i++){
            edge &e=G[v][i];
            if(e.cap>0&&level[e.to]<0){
                level[e.to]=level[v]+1;
                que.push(e.to);
            }
        }
    }
}
int dfs(int v,int t,int f){
    if(v==t) return f;
    for(int &i=iter[v];i<G[v].size();i++){
        edge &e=G[v][i];
        if(e.cap>0&&level[v]<level[e.to]){
            int d=dfs(e.to,t,min(f,e.cap));
            if(d>0){
                e.cap-=d;
                G[e.to][e.rev].cap+=d;
                return d;
            }
        }
    }
    return 0;
}
int max_flow(int s,int t){
    int flow=0;
    while(1){
        bfs(s);
        if(level[t]<0) return flow;
        memset(iter,0,sizeof(iter));
        int f;
        while((f=dfs(s,t,inf))>0) flow+=f;
    }
}
int L[maxn][maxn],R[maxn][maxn],n,m;
void slove(int ask){
    int a,b,d;
    char ch;
    for(int k=0;k<ask;k++){
        scanf("%d%d %c%d",&a,&b,&ch,&d);
        if(a==0&&b==0){
            if(ch=='>'){
                for(int i=1;i<=n;i++)
                for(int j=1;j<=m;j++){
                if(R[i][j+n]<=d) flag=1;
                L[i][j+n]=max(L[i][j+n],d+1);
                }
            }else if(ch=='='){
                for(int i=1;i<=n;i++)
                for(int j=1;j<=m;j++){
                if(L[i][j+n]>d) flag=1;
                if(R[i][j+n]<d) flag=1;
                L[i][j+n]=R[i][j+n]=d;
                }
            }else if(ch=='<'){
                for(int i=1;i<=n;i++)
                for(int j=1;j<=m;j++){
                if(L[i][j+n]>=d) flag=1;
                R[i][j+n]=min(R[i][j+n],d-1);
                }
            }
        }
        if(a==0&&b!=0){
            if(ch=='>'){
                for(int i=1;i<=n;i++){
                if(R[i][b+n]<=d) flag=1;
                L[i][b+n]=max(L[i][b+n],d+1);
                }
            }else if(ch=='='){
                for(int i=1;i<=n;i++){
                if(L[i][b+n]>d) flag=1;
                if(R[i][b+n]<d) flag=1;
                L[i][b+n]=R[i][b+n]=d;
                }
            }else if(ch=='<'){
                for(int i=1;i<=n;i++){
                if(L[i][b+n]>=d) flag=1;
                R[i][b+n]=min(R[i][b+n],d-1);
                }
            }
        }
        if(b==0&&a!=0){
            if(ch=='>'){
                for(int i=1;i<=m;i++){
                if(R[a][i+n]<=d) flag=1;
                L[a][i+n]=max(L[a][i+n],d+1);
                }
            }else if(ch=='='){
                for(int i=1;i<=m;i++){
                if(L[a][i+n]>d) flag=1;
                if(R[a][i+n]<d) flag=1;
                L[a][i+n]=R[a][i+n]=d;
                }
            }else if(ch=='<'){
                for(int i=1;i<=m;i++){
                if(L[a][i+n]>=d) flag=1;
                R[a][i+n]=min(R[a][i+n],d-1);
                }
            }
        }
        if(a!=0&&b!=0){
            if(ch=='>'){
                if(R[a][b+n]<=d) flag=1;
                L[a][b+n]=max(L[a][b+n],d+1);
            }else if(ch=='='){
                if(R[a][b+n]<d) flag=1;
                if(L[a][b+n]>d) flag=1;
                L[a][b+n]=R[a][b+n]=d;
            }else if(ch=='<'){
                if(L[a][b+n]>=d) flag=1;
                R[a][b+n]=min(R[a][b+n],d-1);
            }
        }
    }
}
int num[10010][5];
int main(){
    int T1,a,ask;
    scanf("%d",&T1);
    while(T1--){
        scanf("%d%d",&n,&m);
        for(int i=0;i<maxn;i++) G[i].clear();
        memset(L,0,sizeof(L));
        memset(R,inf,sizeof(R));
        int S=n+m+2,T=n+m+3,sum=0,kk=0;
        int sum1=0,sum2=0;
        for(int i=1;i<=n;i++){
            scanf("%d",&a);sum1+=a;
            add_edge(0,i,a);
        }
        for(int i=1;i<=m;i++){
            scanf("%d",&a);sum2+=a;
            add_edge(i+n,n+m+1,a);
        }
        add_edge(n+m+1,0,inf);
        int kkkk=G[n+m+1].size()-1;
        scanf("%d",&ask);
        flag=0;
        slove(ask);
        if(flag||sum1!=sum2){
            printf("IMPOSSIBLE\n\n");
            continue;
        }
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                add_edge(i,j+n,R[i][j+n]-L[i][j+n]);
                sum+=L[i][j+n];
                num[kk][0]=i,num[kk][1]=G[i].size()-1;kk++;
                add_edge(S,j+n,L[i][j+n]);add_edge(i,T,L[i][j+n]);
            }
        }
        int ans=max_flow(S,T);
        if(ans!=sum) printf("IMPOSSIBLE\n");
        else{
            G[n+m+1][kkkk].cap=0;
            int aaa=max_flow(0,n+m+1);
            int tt=0;
            for(int i=1;i<=n;i++){
                for(int j=1;j<=m;j++){
                    if(j!=m) printf("%d ",R[i][j+n]-G[num[tt][0]][num[tt][1]].cap);
                    else printf("%d\n",R[i][j+n]-G[num[tt][0]][num[tt][1]].cap);
                    tt++;
                }
            }
        }
        printf("\n");
    }
    return 0;
}

有点上   PS:这题的建图麻烦的要死.....只有细心才能1A....

时间: 2024-10-06 18:24:35

POJ 2396 有源汇上下界判断可行解的相关文章

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

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

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

[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

zoj 3229 Shoot the Bullet(有源汇上下界最大流)

Shoot the Bullethttp://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=3442 Time Limit: 2 Seconds      Memory Limit: 32768 KB      Special Judge Gensokyo is a world which exists quietly beside ours, separated by a mystical border. It is a utopia

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

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

zoj3229 有源汇上下界最大流

题意:有一个人每天给妹子拍照,每个妹子有最少拍照数,每天有最大拍照数,每天只能给某些特定的妹子拍照,求最大拍照数 题解:很容易看出来的有源汇上下界最大流,对于有源汇 的上下界最大流,我们按照无源汇的操作连边,然后从汇点连一条边到源点,容量无穷大,下界为0,从超级源ss到超级汇tt跑一遍最大流,求得的流量就是可行流 的流量,此时求出来的只是可行流并不是最大流,我们还需要从原来的s到t跑一边最大流,最后的最大流就是可行流 的流量+新增广的s-t流量 ps:这题样例一直过不了,但是我发现很多博客代码的

hdu3157有源汇上下界最小流

题意:有源汇上下界最小流裸题,主要就是输入要用字符串的问题 #include<bits/stdc++.h> #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 10000000

sgu176 有源汇上下界最小流

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

[hdu] 3157 Crazy Circuits || 有源汇上下界最小流

原题 有两个正负极n个节点和m个元件,每个元件告诉端点是接在哪个节点上的,并且每个元件有工作的最小电流限制,问使所有元件工作的满足条件的最小电流是多少. 有源汇上下界最小流. 考虑dinic的推流思想,所以在跑完可行流后,减去t到s的最大流就是最小流. 实现方法: 建图时先不加入t到s的inf边,跑最大流,再加入inf边跑最大流.若此刻是可行流,那么加入的t到s的inf边的反向边的权值就是最小流. ll ans=0; ans+=dinic(); add(t,s,inf); ans+=dinic(