本文主要是介绍poj 2396 zoj 1994 Budget(有源汇上下界的可行流),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
思路:
无源汇 (附加源汇+最大解决)
有源汇 (附加(T,S)->无源汇)
Time Limit: 3000MS | Memory Limit: 65536K | |||
Total Submissions: 6237 | Accepted: 2367 | Special Judge |
Description
And, by the way, no one really reads budget proposals anyway, so we'll just have to make sure that it sums up properly and meets all constraints.
Input
Each constraint consists of two integers r and q, specifying some entry (or entries) in the matrix (the upper left corner is 1 1 and 0 is interpreted as "ALL", i.e. 4 0 means all entries on the fourth row and 0 0 means the entire matrix), one element from the set {<, =, >} and one integer v, with the obvious interpretation. For instance, the constraint 1 2 > 5 means that the cell in the 1st row and 2nd column must have an entry strictly greater than 5, and the constraint 4 0 = 3 means that all elements in the fourth row should be equal to 3.
Output
Sample Input
22 3
8 10
5 6 7
4
0 2 > 2
2 1 = 3
2 3 > 2
2 3 < 5 2 2
4 5
6 7
1
1 1 > 10
Sample Output
2 3 3
3 3 4 IMPOSSIBLE
首先要根据题目要求构造出一个容量网络 然后根据网络建图跑最大流 得到可行流
容量网络的构造方法:
如图 构造一个源点s(0) 一个汇点t(n+m+1) 源点与每行的节点建边 权值为每行的总和
每列的节点与汇点之间建边 权值为每列的总和
每行每列之间有上下界 根据题目的要求求出low[i][j] high[i][j]
然后判断有木有不合理的情况 不合理的直接输出IMPOSSIBLE
之后开始建图求最大流
超级源点ss(n+m+2) 超级汇点tt(n+m+3)
每行的节点i与每列的节点j连接 i->j权值为high[i][j]-low[i][j]
容量网络里的每个点与ss或tt连接 out[i]为正与ss连接 权值为out[i]
out[i]为负与tt连接 权值为-out[i]
容量网络中s t之间也要建边 t->s权值INF
细节部门就是数据的读取处理出low[i][j] high[i][j] out[i]
<span style="font-family:KaiTi_GB2312;font-size:18px;">#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string.h>
#include <string>
#include <queue>
#include <vector>#define MEM(a,x) memset(a,x,sizeof a)
#define eps 1e-8
#define MOD 10009
#define MAXN 10010
#define INF 0x3fffffff
#define ll __int64
#define bug cout<<"here"<<endl;
#define fread freopen("ceshi.txt","r",stdin)
#define fwrite freopen("out.txt","w",stdout)using namespace std;void read(int &x)
{char ch;x=0;while(ch=getchar(),ch!=' '&&ch!='\n'){x=x*10+ch-'0';}
}struct Edge
{int from,to,cap,flow;bool operator <(const Edge e) const{if(e.from!=from) return from<e.from;else return to<e.to;}Edge() {}Edge(int from,int to,int cap,int flow):from(from),to(to),cap(cap),flow(flow) {}
};struct Dinic
{vector<Edge> edges;vector<int> G[MAXN];bool vis[MAXN];//BFS使用int d[MAXN]; //从起点到i的距离int cur[MAXN]; //当前弧下标int n,m,s,t,maxflow; //节点数 边数(包括反向弧) 源点编号和弧点编号void init(int n){this->n=n;for(int i=0;i<=n;i++)G[i].clear();edges.clear();}void addedge(int from,int to,int cap){edges.push_back(Edge(from,to,cap,0));edges.push_back(Edge(to,from,0,0));m=edges.size();G[from].push_back(m-2);G[to].push_back(m-1);}bool bfs(){MEM(vis,0);MEM(d,-1);queue<int> q;q.push(s);d[s]=maxflow=0;vis[s]=1;while(!q.empty()){int u=q.front(); q.pop();int sz=G[u].size();for(int i=0;i<sz;i++){Edge e=edges[G[u][i]];if(!vis[e.to]&&e.cap>e.flow){d[e.to]=d[u]+1;vis[e.to]=1;q.push(e.to);}}}return vis[t];}int dfs(int u,int a){if(u==t||a==0) return a;int sz=G[u].size();int flow=0,f;for(int &i=cur[u];i<sz;i++){Edge &e=edges[G[u][i]];if(d[u]+1==d[e.to]&&(f=dfs(e.to,min(a,e.cap-e.flow)))>0){e.flow+=f;edges[G[u][i]^1].flow-=f;flow+=f;a-=f;if(a==0) break;}}return flow;}int Maxflow(int s,int t){this->s=s; this->t=t;int flow=0;while(bfs()){MEM(cur,0);flow+=dfs(s,INF);}return flow;}
}Dic;int out[250];
int low[300][300];
int high[300][300];
int r[220],c[30];int main()
{
// fread;int tc;scanf("%d",&tc);int cs=0;while(tc--){int n,m;scanf("%d%d",&n,&m);MEM(out,0);int line=0; int col=0;for(int i=1;i<=n;i++){int num;scanf("%d",&num);line+=num;out[0]-=num;out[i]+=num;}for(int j=1;j<=m;j++){int num;scanf("%d",&num);col+=num;out[n+m+1]+=num;out[j+n]-=num;}//out记录进入/出去 节点的流量 为正与源点建边 为负与汇点建边for(int i=0;i<300;i++)for(int j=0;j<300;j++){low[i][j]=0;high[i][j]=INF;}int ca;scanf("%d",&ca);int flag=0;while(ca--){int u,v,w;char ch;scanf("%d %d %c %d",&u,&v,&ch,&w);if(u==0&&v==0){for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){if(ch=='>') low[i][j+n]=max(low[i][j+n],w+1);if(ch=='<') high[i][j+n]=min(high[i][j+n],w-1);if(ch=='=') low[i][j+n]=high[i][j+n]=w;if(low[i][j+n]>high[i][j+n])flag=1;}}else if(u==0){for(int i=1;i<=n;i++){if(ch=='>') low[i][v+n]=max(low[i][v+n],w+1);if(ch=='<') high[i][v+n]=min(high[i][v+n],w-1);if(ch=='=') low[i][v+n]=high[i][v+n]=w;if(low[i][v+n]>high[i][v+n])flag=1;}}else if(v==0){for(int j=1;j<=m;j++){if(ch=='>') low[u][j+n]=max(low[u][j+n],w+1);if(ch=='<') high[u][j+n]=min(high[u][j+n],w-1);if(ch=='=') low[u][j+n]=high[u][j+n]=w;if(low[u][j+n]>high[u][j+n])flag=1;}}else{if(ch=='>') low[u][v+n]=max(low[u][v+n],w+1);if(ch=='<') high[u][v+n]=min(high[u][v+n],w-1);if(ch=='=') low[u][v+n]=high[u][v+n]=w;if(low[u][v+n]>high[u][v+n])flag=1;}}if(cs) puts("");cs=1;if(flag||line!=col){puts("IMPOSSIBLE");continue;}int s=n+m+2,t=n+m+3;Dic.init(t);for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){out[i]-=low[i][j+n];out[j+n]+=low[i][j+n];Dic.addedge(i,j+n,high[i][j+n]-low[i][j+n]);}}Dic.addedge(n+m+1,0,INF);int sum=0;for(int i=0;i<=n+m;i++){if(out[i]>0){sum+=out[i];Dic.addedge(s,i,out[i]);}elseDic.addedge(i,t,-out[i]);}int mx=Dic.Maxflow(s,t);
// cout<<mx<<endl;
// cout<<"sum "<<sum<<endl;
// int ffff=(Dic.Maxflow(s,t)==sum);
// cout<<ffff<<endl;if(mx!=sum){
// bug;puts("IMPOSSIBLE");continue;}
// for(int i=0;i<n*m;i++)
// {
// int u=Dic.edges[i*2].from,v=Dic.edges[i*2].to;
// cout<<"iii "<<i<<endl;
// cout<<u<<" "<<v<<" "<<Dic.edges[i*2].flow+low[u][v]<<endl;
// }int id=0;for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){if(j==1){printf("%d",Dic.edges[id*2].flow+low[i][j+n]);}elseprintf(" %d",Dic.edges[id*2].flow+low[i][j+n]);id++;}printf("\n");}
// if(tc)
// puts("");}return 0;
}
</span>
这篇关于poj 2396 zoj 1994 Budget(有源汇上下界的可行流)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!