Flow construction SGU - 176 有源汇有上下界最小流 二分法和回流法
/** 题目:Flow construction SGU - 176
链接:https://vjudge.net/problem/SGU-176
题意:
有源汇有上下界的最小流。
给定n个点,m个管道。每个管道给出u,v,z,c。u表示起点,v表示终点,z表示容量,如果c==1,那么表示还有下界为z。
如果c==0,表示没有下界。
求从1到n的最小流。
思路:
第一种做法:
转化为无源汇求超级源S到超级汇T的最大流flow1(此时从s出发的流和为flow1),然后讲t到s的边删掉(可以使流量等于容量,这样求t到s的最大流就不会经过他了。)
求t到s的最大流flow2(从s出发的流减少的量).是为了回流,因为原先求flow1的过程,是为了满足下界的可行流。这个在原图的可行流可能可以变得更小,通过回流使其缩小。
求t到s的最大流并不会影响原来附加边的流量。所以保证了是下界满足的可行流。
然后用flow1-flow2就是结果。 第二种做法:
构造无源汇有上下界的可行流做法,只不过t到s的边的上下界要改一下。
二分t到s的上界a,下界为0,如果是可行流最小的a便是最小流。如果是求最大流,那么就是二分t到s的下界a,上界无穷,如果是可行流,那么最大的a便是最大流。
不懂的看文档解释。https://wenku.baidu.com/view/0f3b691c59eef8c75fbfb35c.html 关于每次二分,处理一次最大流,那么下次在计算最大流的时候,难道又要重新建图?
反正是结构体存的,新加一个变量存储。下次直接从这个变量获取即可。注意t到s这条边的修改。或者最后面再加进去。 */ 第一种做法 #include<iostream>
#include<cstring>
#include<vector>
#include<map>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
const int INF = 0x3f3f3f3f;
typedef long long LL;
const int N = ;///n+m=1365
int in[N];
int out[N];
struct Edge{
int from, to, cap, flow;
Edge(int u,int v,int c,int f):from(u),to(v),cap(c),flow(f){}
};
struct Dinic{
int n, m, s, t;
vector<Edge> edges;
vector<int> G[N];
bool vis[N];
int d[N];
int cur[N]; void init(int n)
{
this->n = n;
for(int i = ; i <= n; i++) G[i].clear();
edges.clear();
} void AddEdge(int from,int to,int cap)
{
edges.push_back(Edge(from,to,cap,));
edges.push_back(Edge(to,from,,));
m = edges.size();
G[from].push_back(m-);
G[to].push_back(m-);
} bool BFS()
{
memset(vis, , sizeof vis);
queue<int> Q;
Q.push(s);
d[s] = ;
vis[s] = ;
while(!Q.empty())
{
int x = Q.front();
Q.pop();
for(int i = ; i < G[x].size(); i++)
{
Edge &e = edges[G[x][i]];
if(!vis[e.to]&&e.cap>e.flow)
{
vis[e.to] = ;
d[e.to] = d[x]+;
Q.push(e.to);
}
}
}
return vis[t];
} int DFS(int x,int a)
{
if(x==t||a==) return a;
int flow = , f;
for(int &i = cur[x]; i < G[x].size(); i++)
{
Edge& e = edges[G[x][i]];
if(d[x]+==d[e.to]&&(f=DFS(e.to,min(a,e.cap-e.flow)))>)
{
e.flow += f;
edges[G[x][i]^].flow -= f;
flow += f;
a -= f;
if(a==) break;
}
}
return flow;
} int Maxflow(int s,int t)
{
this->s = s, this->t = t;
int flow = ;
while(BFS())
{
memset(cur, , sizeof cur);
flow += DFS(s,INF);
}
return flow;
}
};
int dw[N*N];
int main()
{
int n, m;
while(scanf("%d%d",&n,&m)==)
{
Dinic dinic;
dinic.init(n+);
int u, v, cap, flag;///1,n为普通源汇。
int s = , t = n+;///超级源汇。
memset(dw, , sizeof dw);
memset(in, , sizeof in);
memset(out, , sizeof out);
for(int i = ; i<m; i++){
scanf("%d%d%d%d",&u,&v,&cap,&flag);
if(flag==){
dw[i] = cap;
dinic.AddEdge(u,v,);
out[u]+=cap;
in[v]+=cap;
}else
{
dinic.AddEdge(u,v,cap); }
}
int ts;
dinic.AddEdge(n,,INF);
ts = dinic.edges.size()-;
int sum = ;
for(int i = ; i <= n; i++){
if(in[i]>out[i]){
dinic.AddEdge(s,i,in[i]-out[i]);
sum += in[i]-out[i];
}
if(in[i]<out[i]){
dinic.AddEdge(i,t,out[i]-in[i]);
}
}
int flow = dinic.Maxflow(s,t);
if(flow!=sum){
printf("Impossible\n"); continue;
}
dinic.edges[ts].cap = dinic.edges[ts].flow;///使其求n到1的最大流无法经过。
int flow2 = dinic.Maxflow(n,);///回流
printf("%d\n",flow-flow2);
for(int i = ; i < m; i++){
if(i==m-){
printf("%d\n",dinic.edges[*i].flow+dw[i]);
}else
{
printf("%d ",dinic.edges[*i].flow+dw[i]);
}
}
}
return ;
} 第二种做法 #include<iostream>
#include<cstring>
#include<vector>
#include<map>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
const int INF = 0x3f3f3f3f;
typedef long long LL;
const int N = ;///n+m=1365
int in[N];
int out[N];
struct Edge{
int from, to, cap, flow;
Edge(int u,int v,int c,int f):from(u),to(v),cap(c),flow(f){}
};
struct Dinic{
int n, m, s, t;
vector<Edge> edges;
vector<int> G[N];
bool vis[N];
int d[N];
int cur[N]; void init(int n)
{
this->n = n;
for(int i = ; i <= n; i++) G[i].clear();
edges.clear();
} void AddEdge(int from,int to,int cap)
{
edges.push_back(Edge(from,to,cap,));
edges.push_back(Edge(to,from,,));
m = edges.size();
G[from].push_back(m-);
G[to].push_back(m-);
} bool BFS()
{
memset(vis, , sizeof vis);
queue<int> Q;
Q.push(s);
d[s] = ;
vis[s] = ;
while(!Q.empty())
{
int x = Q.front();
Q.pop();
for(int i = ; i < G[x].size(); i++)
{
Edge &e = edges[G[x][i]];
if(!vis[e.to]&&e.cap>e.flow)
{
vis[e.to] = ;
d[e.to] = d[x]+;
Q.push(e.to);
}
}
}
return vis[t];
} int DFS(int x,int a)
{
if(x==t||a==) return a;
int flow = , f;
for(int &i = cur[x]; i < G[x].size(); i++)
{
Edge& e = edges[G[x][i]];
if(d[x]+==d[e.to]&&(f=DFS(e.to,min(a,e.cap-e.flow)))>)
{
e.flow += f;
edges[G[x][i]^].flow -= f;
flow += f;
a -= f;
if(a==) break;
}
}
return flow;
} int Maxflow(int s,int t)
{
this->s = s, this->t = t;
int flow = ;
while(BFS())
{
memset(cur, , sizeof cur);
flow += DFS(s,INF);
}
return flow;
}
};
int dw[N*N];
int main()
{
int n, m;
while(scanf("%d%d",&n,&m)==)
{
Dinic dinic;
dinic.init(n+);
int u, v, cap, flag;///1,n为普通源汇。
int s = , t = n+;///超级源汇。
memset(dw, , sizeof dw);
memset(in, , sizeof in);
memset(out, , sizeof out);
for(int i = ; i<m; i++){
scanf("%d%d%d%d",&u,&v,&cap,&flag);
if(flag==){
dw[i] = cap;
dinic.AddEdge(u,v,);
out[u]+=cap;
in[v]+=cap;
}else
{
dinic.AddEdge(u,v,cap); }
}
int sum = ;
for(int i = ; i <= n; i++){
if(in[i]>out[i]){
dinic.AddEdge(s,i,in[i]-out[i]);
sum += in[i]-out[i];
}
if(in[i]<out[i]){
dinic.AddEdge(i,t,out[i]-in[i]);
}
}
Dinic Tdinic = dinic;
int flow;
int lo = , hi = INF, mid;
while(lo<hi){///最小流,二分上界,取最小值。
mid = (lo+hi)/;
dinic = Tdinic;
dinic.AddEdge(n,,mid);
flow = dinic.Maxflow(s,t);
if(flow!=sum){
lo = mid+;
}else
{
hi = mid;
}
}
if(hi==lo){
printf("Impossible\n"); continue;
}
printf("%d\n",hi);
dinic = Tdinic;///注意复原,因为此时的dinic不是最小流为hi的时候的。要重新计算。
dinic.AddEdge(n,,hi);
dinic.Maxflow(s,t);
for(int i = ; i < m; i++){
if(i==m-){
printf("%d\n",dinic.edges[*i].flow+dw[i]);
}else
{
printf("%d ",dinic.edges[*i].flow+dw[i]);
}
}
}
return ;
}
Flow construction SGU - 176 有源汇有上下界最小流 二分法和回流法的更多相关文章
- loj #117. 有源汇有上下界最小流
题目链接 有源汇有上下界最小流,->上下界网络流 注意细节,边数组也要算上后加到SS,TT边. #include<cstdio> #include<algorithm> ...
- LOJ.117.[模板]有源汇有上下界最小流(Dinic)
题目链接 有源汇有上下界最小流 Sol1. 首先和无源汇网络流一样建图,求SS->TT最大流: 然后连边(T->S,[0,INF]),再求一遍SS->TT最大流,答案为新添加边的流量 ...
- sgu 176 Flow construction(有源汇的上下界最小流)
[题目链接] http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=11025 [模型] 有源汇点的上下界最小流.即既满足上下界又满足 ...
- sgu176 Flow Construction【有源汇有上下界最小流】
同样是模板题. 首先将有源汇转换为无源汇,假设原来的源汇为st,我们加入的源汇为ST,那么我们应该从t到s连一条流量为+∞的边,使原来的st满足收支平衡,退化为普通节点. 分离必要边和其他边,从S到T ...
- sgu 176 有源汇有上下界的最小流模板题
/*参考博文:http://hi.baidu.com/dragon_eric123/item/82e259200ece744046996282 有上下界的有源最小流 */ #include<st ...
- 【 POJ - 3801】Crazy Circuits(有源汇、上下界最小流)
Description You’ve just built a circuit board for your new robot, and now you need to power it. Your ...
- bzoj 2502 清理雪道(有源汇的上下界最小流)
[题意] 有一个DAG,要求每条边必须经过一次,求最少经过次数. [思路] 有上下界的最小流. 边的下界为1,上界为无穷.构造可行流模型,先不加ts边跑一遍最大流,然后加上t->s的inf边跑 ...
- LOJ117 有源汇有上下界最小流(上下界网络流)
跑出可行流后从原来的汇点向原来的源点跑最大流,原图最小流=inf-maxflow.显然超源超汇的相关边对其也没有影响.原图最小流=可行流-原图新增流量,因为t向s流量增加相当于s向t流量减少.但为什么 ...
- Crazy Circuits HDU - 3157(有源汇有上下界最小流)
给出每条边的下界 求最小流 板题 提供两个板子代码 虽然这个题 第一个比较快 但在loj上https://loj.ac/problem/117 的板题 第一个1700+ms 第二个才600+ms ...
随机推荐
- 【Web】Django OAuth invalid_grant error
This can happen if the code is expired. They expire pretty quickly by default. You can look up your ...
- phpstorm快速跳转到错误行
phpstorm的快捷键,在网上可以搜索出很多,唯有“快速跳到错误行”的快捷键几乎搜索不出来. 看着错误提示,要一行一行的用眼睛去看,心累. 贴在这里,随时取用,再也不怕忘记了. Shift + F2 ...
- javascript 中用到的时间戳函数
JavaScript 获取当前时间戳:第一种方法: var timestamp = Date.parse(new Date()); 例如结果:1280977330000第二种方法: var times ...
- nginx安装说明
下载地址:http://nginx.org/en/download.html 安装版本:1.10.0 安装配置如下: /etc/nginx 目录 /home/nginx目录 --prefix=/hom ...
- 做一个创建cocos2d-x新项目的shell脚本
1. 进入console目录 cd /Users/apple/Documents/MyArchitecture/Cocos2d-x/Framework/cocos2d-x-3.4/tools/coco ...
- Hibernate关系映射(注解)
1.类级别注解 @Entity 映射实体类 @Table 映射数句库表 @Entity(name="tableName") - 必须,注解将一个类声明为一个实体bea ...
- python 字典的KeyError处理方法
先看一段代码: user = dict(name="brainliao", age=32) print(user["sex"]) 运行结果如下: user这个字 ...
- iOS项目开发实战——使用CoreLocation获取当前位置信息
随着基于位置服务LBS和移动互联网的兴起,你的位置是越来越重要的一个信息.位置服务已经是当前的热门应用如微信.陌陌等社交应用的杀手锏.而在iOS开发中,苹果已经给我们提供了一个位置接口.CoreLoc ...
- 算法笔记_056:蓝桥杯练习 未名湖边的烦恼(Java)
目录 1 问题描述 2 解决方案 2.1 递归法 2.2 递推法 1 问题描述 问题描述 每年冬天,北大未名湖上都是滑冰的好地方.北大体育组准备了许多冰鞋,可是人太多了,每天下午收工后,常常一双冰 ...
- Ubuntu 下apache2 增加新的module
http://andrew913.iteye.com/blog/398648 首先来介绍下apache的一个工具apxs.apxs是一个为Apache HTTP服务器编译和安装扩展模块的工具,用于编译 ...