POJ-2396-Budget

Posted no-longer

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ-2396-Budget相关的知识,希望对你有一定的参考价值。

【题目大意】

  有一n*m的矩阵,但其间的具体数值未知,但知道某些元素值在某个区间内,再给出每行的和及每列的和,求任意一种可行方案,无解输出"IMPOSSIBLE"。(Special Judge)

  链接: POJ2396

【思路】

  每行每列的和等于总和,考虑网络流(许多流量元素流到一起,汇总到一条边),某个元素有上下界,考虑有上下界的网络流。

  流过的流量表示元素的真实数值,元素上下界对应网络流中的上下界,求解有源汇的网络流即可。

【建模方式】

  以每以行为一个X点,每一列为一个Y点,建立二分图。附加源点S,汇点T,连边 S -> X 流量范围为[每行的和,每行的和],Y -> T 流量范围为[每列的和,每列的和]。

  连边 X -> Y 流量范围为[X行Y列元素下界,X行Y列元素上界]。问题转换为有源汇有上下界的可行流,最后沿残量网络上的边输出结果。

【代码】

#include<queue>
#include<cstdio>
#include<cstring>
using namespace std;
const int MAX_N=22,MAX_M=243,INF=0x3f3f3f3f;
struct Edge{
    int from,to,flow,next;
};
class ISAP {
    static const int maxm=80010;
    static const int maxn=410;
    int n,s,t,len;
    bool vis[maxn];
    int dis[maxn];
    int cur[maxn];
    int p[maxn];
    int num[maxn];
    inline bool rev_bfs(void){
        memset(vis,0,sizeof(vis));
        queue<int> q;
        q.push(t);
        dis[t]=0;
        vis[t]=1;
        while(!q.empty()){
            int x=q.front();
            q.pop();
            for(register int i=head[x];i;i=edges[i].next){
                Edge &e=edges[i^1];
                if(!vis[e.from]&&e.flow>0){
                    vis[e.from]=1;
                    dis[e.from]=dis[x]+1;
                    q.push(e.from);
                }
            }
        }
        return vis[s];
    }
    inline int augment(){
        int x=t,mx=INF;
        while(x!=s){
            Edge &e=edges[p[x]];
            mx=min(mx,e.flow);
            x=e.from;
        }
        x=t;
        while(x!=s){
            edges[p[x]].flow-=mx;
            edges[p[x]^1].flow+=mx;
            x=edges[p[x]].from;
        }
        return mx;
    }
public:
    Edge edges[maxm<<1];
    int head[maxn];
    inline void reset(){
        memset(head,0,sizeof(head));
        len=1;
    }
    inline ISAP(void){
        memset(head,0,sizeof(head));
        len=1;
    }
    inline void ins(int from,int to,int flow,int rev=0){
        edges[++len]=((Edge){from,to,flow,head[from]});
        head[from]=len;
        edges[++len]=((Edge){to,from,rev,head[to]});
        head[to]=len;
    }
    inline int max_flow(int s,int t,int n){
        this->s=s,this->t=t,this->n=n;
        int flow=0;
        rev_bfs();
        memset(num,0,sizeof(num));
        for(int i=0;i<n;i++)
            num[dis[i]]++;
        int x=s;
        memcpy(cur,head,sizeof(cur));
        while(dis[s]<n){
            
            if(x==t){
                flow+=augment();
                x=s;
            }
            bool tf=false;
            for(register int &i=cur[x];i;i=edges[i].next){
                Edge &e=edges[i];
                if(e.flow>0&&dis[x]==dis[e.to]+1){
                    tf=true;
                    p[e.to]=i;
                    x=e.to;
                    break;
                }
            }
            
            if(!tf){
                int m=n-1;
                for(register int i=head[x];i;i=edges[i].next){
                    Edge &e=edges[i];
                    if(e.flow>0)
                        m=min(m,dis[e.to]);
                }
                if(--num[dis[x]]==0)
                    break;
                num[dis[x]=m+1]++;
                cur[x]=head[x];
                if(x!=s)
                    x=edges[p[x]].from;
            }
        }
        return flow;
    }
}solve;

int low[MAX_M][MAX_M],up[MAX_M][MAX_M],cnt[MAX_M],
    row,col,s,t;
bool tfs;

bool change(int u,int v,char ch,int flow) {
    if(ch=='='){
            if(low[u][v]>flow || up[u][v] < flow)
                return false;
            low[u][v]=up[u][v]=flow;
    }else if(ch=='>')
        low[u][v]=max(low[u][v],flow+1);
    else
        up[u][v]=min(up[u][v],flow-1);
    return (low[u][v]<=up[u][v]);
}

void read() {
    int flow,num,tn,tm;
    char choose;
    for(int i=1;i<=row;i++) {
        scanf("%d",&flow);
        low[s][i]=up[s][i]=flow;
    }

    for(int i=1;i<=col;i++) {
        scanf("%d",&flow);
        low[i][t]=up[i][t]=flow;
    }
    scanf("%d",&num);
    while(num--) {
        scanf("%d %d %c %d",&tn,&tm,&choose,&flow);
        if(tn&&tm&&tfs)
            tfs=change(tn,tm,choose,flow);
        else if(!tn&&tm&&tfs)
            for(int i=1;i<=row;i++)
                tfs=change(i,tm,choose,flow);
        else if(tn&&!tm&&tfs)
            for(int j=1;j<=col;j++)
                tfs=change(tn,j,choose,flow);
        else if(tfs)
            for(int i=1;i<=row;i++)
                for(int j=1;j<=col;j++)
                    tfs=change(i,j,choose,flow);
    }
}
bool flows() {
    int SS=t+1,TT=t+2,sum=0;
    for(int i=1;i<=row;i++)
        for(int j=1;j<=col;j++) {
            //上下界网络流建边 
            solve.ins(i,j+row,up[i][j]-low[i][j]);
            cnt[i]-=low[i][j],cnt[j+row]+=low[i][j];
        }
    for(int i=1;i<=row;i++) {
        solve.ins(s,i,0);
        cnt[s]-=low[s][i];
        cnt[i]+=low[s][i];
    }
    for(int j=1;j<=col;j++) {
        solve.ins(j+row,t,0);
        cnt[j+row]-=low[j][t];
        cnt[t]+=low[j][t];
    }
    solve.ins(t,s,INF);
    for(int i=1;i<=t;i++)
        if(cnt[i]>0) {
            solve.ins(SS,i,cnt[i]);
            sum+=cnt[i];
        } else
            solve.ins(i,TT,-cnt[i]);

    //网络流 
    int ans;
    if((ans=solve.max_flow(SS,TT,TT+5))!=sum)
        return false;
    else
        return true;
}

int main() {
    int test;
    scanf("%d",&test);
    while(test--) {
        //清空信息 
        tfs=true;
        memset(cnt,0,sizeof(cnt));
        memset(low,0,sizeof(low));
        memset(up,INF,sizeof(up));
        solve.reset();
        
        //读入 
        scanf("%d%d",&row,&col);
        s=row+col+1,t=s+1;
        read();
        
        //网络流 
        if(tfs)
            tfs=flows();
        if(!tfs) {
            printf("IMPOSSIBLE\n");
            continue;
        }
        
        //输出 
        int v,print[MAX_M][MAX_N];
        for(int i=1;i<=row;i++) {
            int k=1;
            for(int j=solve.head[i];j ;j=solve.edges[j].next) {
                v=solve.edges[j].to;
                if(v>=row+1&&v<=row+col)
                    print[i][k++]=solve.edges[j^1].flow+low[i][v-row];
            }
        }
        for(int i=1;i<=row;i++) {
            for(int j=col;j>0;j--)
                printf("%d ",print[i][j]);
            printf("\n");
        }
        printf("\n");
    }
    return 0;
}

以上是关于POJ-2396-Budget的主要内容,如果未能解决你的问题,请参考以下文章

POJ-2396-Budget

poj2396 Budget 有源汇上下界可行流

POJ 2396 Budget(有源汇上下界网络流)

POJ 2396 Budget (有源汇有上下界最大流)

POJ2396 Budget 带下界的最大流

POJ 2396 Budget 有上下界的网络流