码迷,mamicode.com
首页 > 其他好文 > 详细

ZOJ1994 & POJ2396:Budget——题解

时间:2018-01-07 14:07:43      阅读:197      评论:0      收藏:0      [点我收藏+]

标签:das   转换   mat   putchar   algo   下界   set   using   emc   

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1994

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

题目大意:给一个m行n列的空矩阵,让你往上面填数(数为非负整数),使得这个矩阵满足:

1.每行/列和等于给定的每行/列和

2.一些限制条件。

限制条件限制了x,y,ch,v,使得x行y列的点的数满足(>or=or<,由ch决定)v。

特别的,如果x=0则代表y列全满足该条件,如果y=0则代表x行全满足该条件,如果全为0则代表全矩阵全满足该条件。

——————————————————————————

有二分图+上下界网络流想法,不难想到先建源汇点,源点到所有的行连一条上下界均为行和的边,所有的列到汇点连一条上下界均为列和的边。

然后整理限制条件,行和列之间连满足所有限制条件的边。

在那之后就是上下界网络流的活了。

注意:

1.可以先判断行和之和如果不等于列和之和的话就是IMPOSSIBLE。

2.限制条件如果不满足的话||第一条发生的话,记得把剩余的限制条件读完再输出。

3.我们其实可以简化,我们其实根本不需要源汇点,于是它其实可以转换成无源汇上下界网络流可行流。

原因:最开始建源汇点的时候我们发现它只连了上下界相同的边,相当于没连,以致到后来跑可行流的时候它根本不会做出任何贡献,所以大可以删掉。

4.IMPOSSIBLE不要打错……

5.ZOJ选手注意,不能填负数,最后一行不能有两个回车。

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=405;
const int M=2000005;
const int INF=1e9;
inline int read(){
    int X=0,w=0;char ch=0;
    while(!isdigit(ch)){w|=ch==-;ch=getchar();}
    while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    return w?-X:X;
}
struct node{
    int nxt,to,w;
}edge[M];
int head[N],du[N],up[205][205],low[205][205];
int cnt=-1,S,T;
bool die[205][205];
inline void add(int u,int v,int w){
    cnt++;
    edge[cnt].to=v;
    edge[cnt].w=w;
    edge[cnt].nxt=head[u];
    head[u]=cnt;
    return;
}
int lev[N],cur[N],dui[N];
bool bfs(int k){
    int r=0;
    for(int i=1;i<=k;i++){
    lev[i]=-1;
    cur[i]=head[i];
    }
    dui[0]=S,lev[S]=0;
    int u,v;
    for(int l=0;l<=r;l++){
    u=dui[l];
    for(int e=head[u];e!=-1;e=edge[e].nxt){
        v=edge[e].to;
        if(edge[e].w>0&&lev[v]==-1){
        lev[v]=lev[u]+1;
        r++;
        dui[r]=v;
        if(v==T)return 1;
        }
    }
    }
    return 0;
}
int dinic(int u,int flow,int k){
    if(u==k)return flow;
    int res=0,delta;
    for(int &e=cur[u];e!=-1;e=edge[e].nxt){
    int v=edge[e].to;
    if(edge[e].w>0&&lev[u]<lev[v]){ 
        delta=dinic(v,min(edge[e].w,flow-res),k); 
        if(delta>0){
        edge[e].w-=delta;
        edge[e^1].w+=delta;
        res+=delta;
        if(res==flow)break; 
        }
    }
    }
    if(res!=flow)lev[u]=-1;
    return res;
}
inline void init(int m,int n){
    memset(head,-1,sizeof(head));
    memset(du,0,sizeof(du));
    memset(die,0,sizeof(die));
    for(int i=1;i<=m;i++){
    for(int j=1;j<=n;j++){
        up[i][j]=INF;
        low[i][j]=0;
    }
    }
    cnt=-1;
    return;
}
inline char getc(){
    char ch= ;
    while(ch== )ch=getchar();
    return ch;
}
int main(){
    int t=read(),num=0;
    while(t--){
        num++;
        if(num>1)puts("");
    int m=read(),n=read();
        init(m,n);
    int tot=0;
    for(int i=1;i<=m;i++){
        int h=read();
        du[i]+=h;
        tot+=h;
    }
    for(int i=1;i<=n;i++){
        int l=read();
        du[i+m]-=l;
        tot-=l;
    }
    int c=read();
    bool flag=1;
    for(int i=1;i<=c;i++){
        int r=read(),q=read(),a,b;
        char ch=getc();
        int v=read();
        if(ch==<){a=0;b=--v;}
        else if(ch==>){a=++v;b=INF;}
        else a=b=v;
        if(!r&&!q){
        for(int j=1;j<=m&&flag;j++){
            for(int k=1;k<=n&&flag;k++){
            if(die[j][k]&&(low[j][k]>b||low[j][k]<a)){
                flag=0;
                break;
            }
            if(ch===){up[j][k]=low[j][k]=v;die[j][k]=1;}
            else if(ch==>)low[j][k]=max(low[j][k],v);
            else up[j][k]=min(up[j][k],v);
            if(low[j][k]>up[j][k])flag=0;
            }
        }
        }else if(!r){
        for(int j=1;j<=m&&flag;j++){
            if(die[j][q]&&(low[j][q]>b||low[j][q]<a)){
            flag=0;
            break;
            }
            if(ch===){up[j][q]=low[j][q]=v;die[j][q]=1;}
            else if(ch==>)low[j][q]=max(low[j][q],v);
            else up[j][q]=min(up[j][q],v);
            if(low[j][q]>up[j][q])flag=0;
        }
        }else if(!q){
        for(int k=1;k<=n&&flag;k++){
            if(die[r][k]&&(low[r][k]>b||low[r][k]<a)){
            flag=0;
            break;
            }
            if(ch===){up[r][k]=low[r][k]=v;die[r][k]=1;}
            else if(ch==>)low[r][k]=max(low[r][k],v);
            else up[r][k]=min(up[r][k],v);
            if(low[r][k]>up[r][k])flag=0;
        }
        }else{
        if(die[r][q]&&(low[r][q]>b||low[r][q]<a)){
            flag=0;
        }
        if(ch===){up[r][q]=low[r][q]=v;die[r][q]=1;}
        else if(ch==>)low[r][q]=max(low[r][q],v);
        else up[r][q]=min(up[r][q],v);
        if(low[r][q]>up[r][q])flag=0;
        }
    }
    if(!flag||tot!=0){
        puts("IMPOSSIBLE");
        continue;
    }
    for(int i=1;i<=m;i++){
        for(int j=1;j<=n;j++){
        add(i,j+m,up[i][j]-low[i][j]);
        add(j+m,i,0);
        du[i]-=low[i][j];
        du[j+m]+=low[i][j];
        }
    }
    S=m+n+1;T=S+1;
    int ans=0,full=0;
    for(int i=1;i<=m+n;i++){
        if(du[i]>0){
        add(S,i,du[i]);
        add(i,S,0);
        full+=du[i];
        }else if(du[i]<0){
        add(i,T,-du[i]);
        add(T,i,0);
        }
    }
    while(bfs(T))ans+=dinic(S,INF,T);
    if(ans!=full)puts("IMPOSSIBLE");
    else{
        for(int i=1;i<=m;i++){
        for(int j=1;j<=n;j++){
            int id=((i-1)*n+j)*2-1;
            printf("%d",low[i][j]+edge[id].w);
            if(j!=n)putchar( );
        }
        puts("");
        }
    }
    }
    return 0;
}

 

ZOJ1994 & POJ2396:Budget——题解

标签:das   转换   mat   putchar   algo   下界   set   using   emc   

原文地址:https://www.cnblogs.com/luyouqi233/p/8227432.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!