• 【poj2396】 Budget


    http://poj.org/problem?id=2396 (题目链接)

    题意

      给出一个矩阵,给出每一行每一列的和,以及若干限制条件,限制了其中每一个元素的上下界,求一种可行的方案使得每一行每一列数的和满足要求。

    Solution

      我已经完全没有网络流思维了,江化了= 。=

      源点向每一行和每一列连上下界都为其对应和的边,行与列之间连边,边的上下界为对应格子的取值范围。然后跑上下界网络流找一条可行流就可以了。

    细节

      mdzz初值设太大爆int了=  =,还有这种事。。

    代码

    // poj2396
    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #include<queue>
    #define LL long long
    #define inf (1ll<<29)
    #define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout)
    using namespace std;
    
    const int maxn=1010;
    int head[maxn],fi[maxn],d[maxn],upp[maxn][maxn],low[maxn][maxn],id[maxn][maxn];
    int n,m,s,c,t,S,T,SS,TT,cnt,sum,flag;
    struct edge {int to,next,w;}e[maxn*maxn];
    
    void link(int u,int v,int w) {
    	e[++cnt]=(edge){v,head[u],w};head[u]=cnt;
    	e[++cnt]=(edge){u,head[v],0};head[v]=cnt;
    }
    bool bfs() {
    	memset(d,-1,sizeof(d));
    	queue<int> q;q.push(s);d[s]=0;
    	while (!q.empty()) {
    		int x=q.front();q.pop();
    		for (int i=head[x];i;i=e[i].next)
    			if (e[i].w && d[e[i].to]<0) d[e[i].to]=d[x]+1,q.push(e[i].to);
    	}
    	return d[t]>0;
    }
    int dfs(int x,int f) {
    	if (x==t || f==0) return f;
    	int w,used=0;
    	for (int i=head[x];i;i=e[i].next) if (e[i].w && d[e[i].to]==d[x]+1) {
    			w=dfs(e[i].to,min(e[i].w,f-used));
    			used+=w,e[i].w-=w,e[i^1].w+=w;
    			if (used==f) return used;
    		}
    	if (!used) d[x]=-1;
    	return used;
    }
    int Dinic(int x,int y) {
    	int flow=0;s=x,t=y;
    	while (bfs()) flow+=dfs(x,inf);
    	return flow;
    }
    void modify(int x,int y,char *r,int val) {
    	if (r[0]=='<') upp[x][y]=min(upp[x][y],val-1);
    	if (r[0]=='>') low[x][y]=max(low[x][y],val+1);
    	if (r[0]=='=') {
    		if (val>=low[x][y] && val<=upp[x][y]) upp[x][y]=low[x][y]=val;
    		else flag=0;
    	}
    }
    
    int main() {
    	int Case;scanf("%d",&Case);
    	while (Case--) {
    		scanf("%d%d",&n,&m);
    		for (int i=1;i<=n;i++)
    			for (int j=1;j<=m;j++) upp[i][j]=1000,low[i][j]=0;
    		memset(head,0,sizeof(head));
    		memset(fi,0,sizeof(fi));
    		S=0,T=n+m+1;SS=T+1,TT=SS+1;
    		cnt=1;sum=0;flag=1;
    		for (int x,i=1;i<=n;i++) {
    			scanf("%d",&x);
    			fi[S]-=x,fi[i]+=x;
    		}
    		for (int x,i=1;i<=m;i++) {
    			scanf("%d",&x);
    			fi[T]+=x,fi[i+n]-=x;
    		}
    		scanf("%d",&c);char ch[10];
    		for (int x,y,z,i=1;i<=c;i++) {
    			scanf("%d%d%s%d",&x,&y,ch,&z);
    			if (!x && !y)
    				for (int j=1;j<=n;j++)
    					for (int k=1;k<=m;k++) modify(j,k,ch,z);
    			else if (!x) for (int j=1;j<=n;j++) modify(j,y,ch,z);
    			else if (!y) for (int j=1;j<=m;j++) modify(x,j,ch,z);
    			else modify(x,y,ch,z);
    		}
    		for (int i=1;i<=n && flag;i++)
    			for (int j=1;j<=m && flag;j++) {
    				if (low[i][j]<=upp[i][j]) {
    					fi[i]-=low[i][j],fi[n+j]+=low[i][j];
    					link(i,n+j,upp[i][j]-low[i][j]);
    					id[i][j]=cnt-1;
    				}
    				else flag=0;
    			}
    		if (!flag) {puts("IMPOSSIBLE
    ");continue;}
    		for (int i=S;i<=T;i++) {
    			if (fi[i]<0) link(i,TT,-fi[i]);
    			else link(SS,i,fi[i]),sum+=fi[i];
    		}
    		link(T,S,inf);
    		if (sum!=Dinic(SS,TT)) {puts("IMPOSSIBLE
    ");continue;}
    		for (int i=1;i<=n;i++) {
    			for (int j=1;j<=m;j++)
    				printf("%d ",low[i][j]+e[id[i][j]^1].w);
    			puts("");
    		}
    		puts("");
    	}
    	return 0;
    }
    
  • 相关阅读:
    类在编写过程中的一些注意事项
    SDUT 2893-B(DP || 记忆化搜索)
    Microsoft.AlphaImageLoader滤镜解说
    解决网页版权符号模糊不清
    oninput,onpropertychange,onchange的使用方法和差别
    VB.net数据库编程(03):一个SQLserver连接查询的简单样例
    使用WinSetupFromUSB来U盘安装windowsXP(不使用win PE系统)
    ActivityManager
    IP协议
    jni编译non-numeric second argument to `wordlist' function错误
  • 原文地址:https://www.cnblogs.com/MashiroSky/p/6680087.html
Copyright © 2020-2023  润新知