POJ 2396 Budget 有上下界的网络流

POJ 2396  Budget

题意简述:给定矩阵(每个元素都是非负整数)各行各列的和,并且限制其中的某些元素,给出一个可行解,特殊评测。矩阵规模小于200*20。

网络流的模型是显而易见的,不过对于这道题,我们要添加两次源和汇。

第一次添加s连接每一行,t连接每一列,容量上下线都是这行或这列的和。

第二次对每条有容量限制的边(u,v)添加 (ss,v)和( u,tt)容量均为( u,v)的下限。

第三次添加(t,s)容量无穷。

对(ss,tt)求最大流,若ss出发和进入tt的边均满流则有解,并且可以直接输出解。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int maxm=200+50,INF=1e+8;
int k,ans[maxm][maxm],cap[maxm][maxm],flow[maxm][maxm],low[maxm][maxm],up[maxm][maxm],n,m;
 vector<int> next[maxm];

int d[maxm],fa[maxm],cur[maxm];
bool vis[maxm];
bool bfs(int s,int t)
{
 memset(vis,0,sizeof(vis));
 memset(d,0,sizeof(d));
 queue<int>q;
 vis[s]=true;q.push(s);
 while(!q.empty())
 	{
 	 int np=q.front();q.pop();
 	 for(int i=0;i<next[np].size();i++)
 	 	{
 	 	 int ne=next[np][i];
 	 	 if(cap[np][ne]<=flow[np][ne]||vis[ne])continue;
 	 	 q.push(ne);
 	 	 vis[ne]=true;
 	 	 d[ne]=d[np]+1;
		}
	}
 return vis[t];
}

int dfs(int now,int t,int flo)
{
 if(now==t||flo==0)return flo;
 int floww=0;
 for(int i=cur[now];i<next[now].size();i++)
 	{
 	 int np=next[now][i];
	 if(d[np]!=d[now]+1)continue;
	 if(cap[now][np]<=flow[now][np])continue;
	 int fn=dfs(np,t,min(flo,cap[now][np]-flow[now][np]));
	 flow[now][np]+=fn;
	 flow[np][now]-=fn;
	 floww+=fn;
	 flo-=fn;
	 if(flo==0)break;
	 cur[now]++;
	}
 return floww;
}
int dinic(int s,int t)
{
 int ans=0;
 while(bfs(s,t))
 	{
 	 memset(cur,0,sizeof(cur));
 	 ans+=dfs(s,t,INF);
	}
 return ans;
}
void find(int s,int t)
{
 memset(d,0,sizeof(d));
 d[s]=INF;
 queue<int>q;
 q.push(s);
 while(!q.empty())
 	{
 	 int u=q.front();
 	 q.pop();
 	 for(int i=0;i<next[u].size();i++)
 	 	{
 	 	 int nextp=next[u][i];
 	 	 if(d[nextp]!=0||(cap[u][nextp]-flow[u][nextp])<=0)continue;
 	 	 d[nextp]=min(d[u],(cap[u][nextp]-flow[u][nextp]));
 	 	 q.push(nextp);
 	 	 fa[nextp]=u;
 	 	 if(nextp==t)
 	 	 	{
 	 	 	 while(!q.empty())q.pop();
 	 	 	 return ;
			}
		}
	}
}
int E_K(int s,int t)
{
 int ans=0;
 memset(fa,0,sizeof(fa));
 while(true)
 	{
 	 find(s,t);
 	 ans+=d[t];
 	 if(d[t]==0)break;
 	 for(int i=t;i!=s;i=fa[i])
 	 	{
 	 	 flow[fa[i]][i]+=d[t];
 	 	 flow[i][fa[i]]-=d[t];
		}
	}
 return ans;
}

void addedge(int a,int b,vector<int> next[])
{
 next[a].push_back(b);
 next[b].push_back(a);
 return ;
}
int main()
{
 int N;
 int s=249,t=s-1,ss=t-1,tt=ss-1;
 scanf("%d",&N);
 for(int ii=1;ii<=N;ii++)
{

     for(int i=0;i<maxm;i++)
     	while(next[i].size()>0)next[i].pop_back();
 	 memset(cap,0,sizeof(cap));memset(flow,0,sizeof(flow));
 	 memset(low,0,sizeof(low));memset(up,0,sizeof(up));
 	 scanf("%d%d",&m,&n);
 	 for(int i=1;i<=m;i++)
 	 	{
 	 	 int a;scanf("%d",&a);
 	 	 cap[s][i]=0;cap[ss][i]+=a;cap[s][tt]+=a;
 	 	 addedge(s,i,next);addedge(ss,i,next);addedge(i,tt,next);
 	 	 for(int j=201;j<=200+n;j++)
 	 	 	{
 	 	 	 addedge(i,j,next);
 	 	 	 up[i][j]=a;
			}
 	 	}
		addedge(s,tt,next);
	 for(int i=201;i<=200+n;i++)
	 	{
	 	 int a;scanf("%d",&a);
	 	 cap[i][t]=0;cap[ss][t]+=a;cap[i][tt]+=a;
	 	 addedge(i,t,next);addedge(i,tt,next);addedge(i,ss,next);
	 	 for(int j=1;j<=m;j++)
	 	 	up[j][i]=min(up[j][i],a);
		}
		addedge(ss,t,next);
 int k;
 scanf("%d",&k);
 for(int iii=0;iii<k;iii++)
 	{
 	 int a,b,c;char t;
 	 scanf("%d%d",&a,&b);t=getchar();t=getchar();scanf("%d",&c);
 	 int ia,ib,ja,jb;
 	 if(a==0){ia=1;ib=m;}
 	 	else {ia=ib=a;}
 	 if(b==0){ja=201;jb=200+n;}
 	 	else{ja=jb=(200+b);}
 	 for(int i=ia;i<=ib;i++)
 	 	for(int j=ja;j<=jb;j++)
 	 		{
 	 		 if(t==‘=‘)
 	 		 	{
 	 		 	 up[i][j]=min(up[i][j],c);low[i][j]=max(low[i][j],c);
				}
			 if(t==‘>‘)
			 	{
			 	 low[i][j]=max(low[i][j],c+1);
				}
			 if(t==‘<‘)
			 	{
			 	 up[i][j]=min(up[i][j],c-1);
				}
			}
	}
 for(int i=1;i<=m;i++)
	 	for(int j=201;j<=200+n;j++)
	 		{
	 		 cap[i][j]=up[i][j]-low[i][j];
	 		 cap[ss][j]+=low[i][j];
	 		 cap[i][tt]+=low[i][j];
			}
 next[t].push_back(s);cap[t][s]=INF;
 dinic(ss,tt);
 bool impo=false;
 for(int i=1;i<=m;i++)
 	{
 	 if(flow[ss][i]!=cap[ss][i]){impo=true;break;}
 	 if(flow[i][tt]!=cap[i][tt]){impo=true;break;}
	}
 for(int j=201;j<=200+n;j++)
 	{
 	 if(flow[ss][j]!=cap[ss][j]){impo=true;break;}
 	 if(flow[j][tt]!=cap[j][tt]){impo=true;break;}
	}
 	 if(flow[s][tt]!=cap[s][tt]){impo=true;}
 	 if(flow[ss][t]!=cap[ss][t]){impo=true;}
 if(impo){printf("IMPOSSIBLE\n\n");continue;}
 for(int i=1;i<=m;i++)
  {

 	for(int j=201;j<n+200;j++)
 		{
 		 printf("%d ",flow[i][j]+low[i][j]);
		}
	 printf("%d\n",flow[i][200+n]+low[i][200+n]);
	}
 printf("\n");
}
 return 0;
}

  

                                    

时间: 2024-12-23 19:12:57

POJ 2396 Budget 有上下界的网络流的相关文章

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

点击打开链接 题意:有一个n行m列的数列,每行元素和的值和每列元素和的值给了你,下面有元素取值的限制条件,如0 0 > 1代表的是这个数列的所有元素都大于1,0代表的就是所有,0 1就是所有行的第一个元素,1 0就是第一行,然后判断是数列在满足这些条件的情况下是否有解 思路:给的条件就是给你上界和下界,然后这题是有源汇点的,源点连行,列连汇点,与HDU4975类似hdu 4975,然后就是将有源汇点的变成无源汇的,只需连一条汇点到源点的inf边即可,然后与无源汇的做法一样,建议不会无源汇的先去学

poj 2396 Budget 边容量有上下界的最大流

题意: 给一个矩阵的每行和及每列和,在给一些行列或点的限制条件.求一个满足的矩阵. 分析: 转化为有上下界的网络流,注意等于也是一种上下界关系,然后用dinic算法. 代码: //poj 2396 //sep9 #include <iostream> #include <queue> #include <algorithm> using namespace std; const int maxN=210; const int maxM=40; const int max

POJ 2396 Budget (有源汇有上下界的可行流)

POJ 2396 Budget 链接:http://poj.org/problem?id=2396 题意:给定一个M*N的矩阵,给定每行每列的和,以及其中一些值的限定条件,问能否构成一个可行的矩阵. 思路: 添加一个源点,向每行连边,每条边的上下界都为该行的和:添加一个汇点,每列向汇点连边,边的上下界都为该列的和.然后每行向每列连边,边的上下界一开始为(0,INF),之后通过一些限定条件更新. 现在问题成了求一个有源汇有上下界的可行流.只需要再添加一个超级源点,一个超级汇点,并且将原图的汇点向源

BZOJ 2406 二分+有上下界的网络流判定

思路: 求出每行的和  sum_row 每列的和   sum_line 二分最后的答案mid S->i  流量[sum_row[i]-mid,sum_row[i]+mid] i->n+j 流量[L,R] n+j->T 流量 [sum_line[i]-mid,sum_line[i]+mid] 套用有上下界的网络流 判一下就好了.. 这是道有上下界网络流的裸题 //By SiriusRen #include <queue> #include <cstdio> #inc

有上下界的网络流2-有源汇带上下界网络流ZOJ3229

ZOJ3229题目大意:一个屌丝给m个女神拍照,计划拍照n天,每一天屌丝可以和C个女神拍照,每天拍照数不能超过D张,而且给每个女神i拍照有数量限制[Li,Ri],对于每个女神n天的拍照总和不能少于Gi,如果有解求屌丝最多能拍多少张照,并求每天给对应女神拍多少张照:否则输出-1. 解题思路:        1.增设一源点st,汇点sd,st到第i天连一条上界为Di下界为0的边,每个女神到汇点连一条下界为Gi上界为正无穷的边,对于每一天,当天到第i个女孩连一条[Li,Ri]的边.        2.

有上下界的网络流1-无源汇带上下界网络流SGU194

今天开始啃网络流了.对于求解无源汇带上下界的网络流,我们可以这样建图:建图模型:         以前写的最大流默认的下界为0,而这里的下界却不为0,所以我们要进行再构造让每条边的下界为0,这样做是为了方便处理.对于每根管子有一个上界容量up和一个下界容量low,我们让这根管子的容量下界变为0,上界为up-low.可是这样做了的话流量就不守恒了,为了再次满足流量守恒,即每个节点"入流=出流",我们增设一个超级源点st和一个超级终点sd.我们开设一个数组du[]来记录每个节点的流量情况.

poj_2396 有上下界的网络流

题目大意 一个mxn的矩阵,给出矩阵中每一行的和sh[1,2...m]以及每一列的数字的和目sv[1,2...n],以及矩阵中的一些元素的范围限制,比如a[1][2] > 1, a[2][3] < 4, a[3][3] = 10等等,且要求矩阵中的每个元素值非负.求出,是否存在满足所有给出的限制条件的矩阵,若存在输出. 题目分析 这么多限制条件..开始只能想到暴力解法+剪枝.这他妈得需要多大的脑洞才能无中生有的想到网络流解法? 不过,给出网络流的想法之后发现采用网络流解法确实很合理,很简单(唯

ZOJ 2314 Reactor Cooling 带上下界的网络流

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1314 题意: 给n个点,及m根pipe,每根pipe用来流躺液体的,单向的,每时每刻每根pipe流进来的物质要等于流出去的物质,要使得m条pipe组成一个循环体,里面流躺物质. 并且满足每根pipe一定的流量限制,范围为[Li,Ri].即要满足每时刻流进来的不能超过Ri(最大流问题),同时最小不能低于Li. 求的是最大流. 很久之前就看了带上下界的网络流,一直没看懂

【网络流补全计划】Part.Ⅲ有上下界的网络流

本来心情就非常糟糕调月下毛景树把我最后一点写代码的心情调没了 放弃 开始补全网络流. 之前学了普通最大流,那么现在开始补有上下界的网络流. 在普通最大流中,网络里的每一条边都只有流量的上界即边的容量,而引入上下界网络流之后,每个边不但有一个容量,还有一个流量下界. 我们令B(u,v)表示边(u,v)的下界.于是我们可以有表达式: B(u,v)≤f(u,v)≤C(u,v) 有这个式子可以得到 0≤f(u,v)≤C(u,v)?B(u,v) 至此,我们可以将有上下界的网络流分为几种问题来对待,接下来就