poj2396 Budget

题目描述:

$T$组询问,每次给出$m,n,q$以及$q$组限制,求一个$m*n$的矩阵,满足:

  1. 每一行/列之和等于给出的每一行/列之和。
  2. 对于每组限制$(x,y,op,w)$(若$x$或$y$为$0$则代表一整行/列),满足所有限制中的元素都大于/等于/小于$w$。

 

题解:

有源汇有上下界可行流板子题+墙题。

每一行/列都看作一个点$x$。矩阵里的数就是相连的边权。

对于限制$1$,可以看作$S$连$x$/$x$连$T$的边上下界都为给出值$k$;

对于限制$2$,可以看作$x$与$y$相连的边上下界修改。

最后按有源汇可行流套路建图即可。

注意$x$可能连$y$,也可能连旧源汇和新源汇……

代码:

#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N = 350;
const int inf = 0x3f3f3f3f;
const ll  Inf = 0x3f3f3f3f3f3f3f3fll;
template<typename T>
inline void read(T&x)
{
    T f = 1,c = 0;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){c=c*10+ch-'0';ch=getchar();}
    x = f*c;
}
int _,m,n,Q,S,T,SS,TT,hed[N],cnt=1;
ll v1[N][2],v2[N][2],v3[N][N][2],v4[2],s[2][N],fin[N],fout[N];
void chkmax(ll&x,ll y){if(x<y)x=y;}
void chkmin(ll&x,ll y){if(x>y)x=y;}
char op[10];
void orz(){puts("IMPOSSIBLE");}
void clear()
{
    memset(hed,0,sizeof(hed));
    memset(fin,0,sizeof(fin));
    memset(fout,0,sizeof(fout));
    for(int i=1;i<=m;i++)
        v1[i][0]=0,v1[i][1]=Inf;
    for(int i=1;i<=n;i++)
        v2[i][0]=0,v2[i][1]=Inf;
    for(int i=1;i<=m;i++)
        for(int j=1;j<=n;j++)
            v3[i][j][0]=0,v3[i][j][1]=Inf;
    v4[0] = 0,v4[1] = Inf;
    cnt = 1;
    S = n+m+1,T = S+1,SS = T+1,TT = SS+1;
}
struct EG
{
    int to,nxt;
    ll fl;
}e[60*N];
void ae(int f,int t,ll fl)
{
    e[++cnt].to = t;
    e[cnt].nxt = hed[f];
    e[cnt].fl = fl;
    hed[f] = cnt;
}
void AE(int f,int t,ll fl)
{
    ae(f,t,fl);
    ae(t,f,0);
}
int cur[N],dep[N];
bool vis[N];
bool bfs()
{
    queue<int>q;
    memcpy(cur,hed,sizeof(cur));
    memset(dep,0x3f,sizeof(dep));
    dep[SS] = 0,vis[SS] = 1;q.push(SS);
    while(!q.empty())
    {
        int u = q.front();
        q.pop();
        for(int j=hed[u];j;j=e[j].nxt)
        {
            int to = e[j].to;
            if(e[j].fl&&dep[to]>dep[u]+1)
            {
                dep[to] = dep[u]+1;
                if(!vis[to])vis[to]=1,q.push(to);
            }
        }
        vis[u] = 0;
    }
    return dep[TT]!=inf;
}
ll dfs(int u,ll lim)
{
    if(u==TT||!lim)return lim;
    ll fl = 0,f;
    for(int j=cur[u];j;j=e[j].nxt)
    {
        cur[u] = j;
        int to = e[j].to;
        if(dep[to]==dep[u]+1&&(f=dfs(to,min(lim,e[j].fl))))
        {
            fl+=f,lim-=f;
            e[j].fl-=f,e[j^1].fl+=f;
            if(!lim)break;
        }
    }
    return fl;
}
ll dinic()
{
    ll ret = 0;
    while(bfs())ret+=dfs(SS,Inf);
    return ret;
}
int main()
{
//    freopen("tt.in","r",stdin);
    read(_);
    while(_--)
    {
        read(m),read(n);
        clear();
        for(int i=1;i<=m;i++)
            read(s[0][i]);
        for(int i=1;i<=n;i++)
            read(s[1][i]);
        read(Q);
        ll w;
        for(int x,y,i=1;i<=Q;i++)
        {
            read(x),read(y);
            scanf("%s",op+1);
            read(w);
            if(op[1]=='=')
            {
                if(x&&y)chkmax(v3[x][y][0],w),chkmin(v3[x][y][1],w);
                else if(!x&&y)chkmax(v2[y][0],w),chkmin(v2[y][1],w);
                else if(x&&!y)chkmax(v1[x][0],w),chkmin(v1[x][1],w);
                else chkmax(v4[0],w),chkmin(v4[1],w);
            }else if(op[1]=='<')
            {
                w--;
                if(x&&y)chkmin(v3[x][y][1],w);
                else if(!x&&y)chkmin(v2[y][1],w);
                else if(x&&!y)chkmin(v1[x][1],w);
                else chkmin(v4[1],w);
            }else
            {
                w++;
                if(x&&y)chkmax(v3[x][y][0],w);
                else if(!x&&y)chkmax(v2[y][0],w);
                else if(x&&!y)chkmax(v1[x][0],w);
                else chkmax(v4[0],w);
            }
        }
        bool ORZ = 0;
        if(v4[0]>v4[1])ORZ=1;
        for(int i=1;!ORZ&&i<=m;i++)
        {
            chkmax(v1[i][0],v4[0]);
            chkmin(v1[i][1],v4[1]);
            if(v1[i][0]>v1[i][1])ORZ=1;
        }
        for(int i=1;!ORZ&&i<=n;i++)
        {
            chkmax(v2[i][0],v4[0]);
            chkmin(v2[i][1],v4[1]);
            if(v2[i][0]>v2[i][1])ORZ=1;
        }
        for(int i=1;!ORZ&&i<=m;i++)
            for(int j=1;!ORZ&&j<=n;j++)
            {
                chkmax(v3[i][j][0],max(v1[i][0],v2[j][0]));
                chkmin(v3[i][j][1],min(v1[i][1],v2[j][1]));
                if(v3[i][j][0]>v3[i][j][1])ORZ=1;
            }
        if(ORZ){orz();continue;}
        
        ll sum = 0;
        for(int i=1;i<=m;i++)
            AE(S,i,0),fin[i]+=s[0][i],fout[S]+=s[0][i];
        for(int i=1;i<=n;i++)
            AE(i+m,T,0),fin[T]+=s[1][i],fout[i+m]+=s[1][i];
        for(int i=1;i<=m;i++)
            for(int j=n;j>=1;j--)
                AE(i,j+m,v3[i][j][1]-v3[i][j][0]),fin[j+m]+=v3[i][j][0],fout[i]+=v3[i][j][0];
        AE(T,S,Inf);
        for(int i=1;i<=T;i++)
            if(fin[i]>fout[i])AE(SS,i,fin[i]-fout[i]),sum+=fin[i]-fout[i];
            else AE(i,TT,fout[i]-fin[i]);
        
        if(sum!=dinic()){orz();continue;}
        else
        {
            for(int i=1;i<=m;puts(""),i++)
                for(int j=hed[i],to;j;j=e[j].nxt)if((to=e[j].to)!=SS&&to!=S&&to!=TT)
                    printf("%lld ",v3[i][to-m][1]-e[j].fl);
            puts("");
        }
    }
    return 0;
}
View Code

 

posted @ 2019-04-21 21:03  LiGuanlin  阅读(92)  评论(0编辑  收藏  举报