ZOJ 2676 Network Wars 最小割 分数规划
2014-09-08 20:45
281 查看
题意:给出一个无向的流网络,其中共有N个点,每个边都有一个权值。顶点1和顶点N之间相互发送信息。现在需要选出几条边,使顶点1和顶点N发出的信息至少经过其中的一条边。我们要最小化这几条边的平均权值。输出选出边的编号。
思路: 这道题的思路在amber的《最小割模型在信息学竞赛中的应用》论文中已经写到。
我就说一下注意点:1.流网络是无向的,所以加边的时候我们要加双向的边。
2.流网络中的容量不能为负,所以对于重赋权的边,如果容量为负,那么一定在最小割中,直接加入最终的结果,而不是加到流网络中。
3.题目中虽然说输出任意方案即可,但仍然需要对边的编号从小到大进行排序。
代码如下:
思路: 这道题的思路在amber的《最小割模型在信息学竞赛中的应用》论文中已经写到。
我就说一下注意点:1.流网络是无向的,所以加边的时候我们要加双向的边。
2.流网络中的容量不能为负,所以对于重赋权的边,如果容量为负,那么一定在最小割中,直接加入最终的结果,而不是加到流网络中。
3.题目中虽然说输出任意方案即可,但仍然需要对边的编号从小到大进行排序。
代码如下:
#include <cstdio> #include <algorithm> #include <cstring> #include <cmath> #include <vector> using namespace std; const double EPS = 1e-7; const double INF = 0x3f3f3f3f; const int MAX = 500; int N,M; int dcmp(double x) { if(fabs(x) < EPS) return 0; else if(x > 0) return 1; else return -1; } struct edge{ int from,to; double cap,flow; int num; edge(int u =0,int v =0,double c=0.0,double f=0.0,int n = 0):from(u),to(v),cap(c),flow(f), num(n){} }; edge a[MAX]; struct ISAP{ static const int MAX = 1000;//2倍的边的大小 int head[MAX];//每个节点对应链表的开始位置 int next[MAX];//链表的下一个节点在edges数组的位置 int tot;//edges数组的大小 edge edges[2 * MAX];//储存边的数组 int que[MAX],front,tail;//队列,保存节点 int d[MAX];//距离标号 bool vis[MAX];//访问标记 int num[MAX];//gap优化 int pre[MAX];//增广路中,节点X的前面一个弧的标号 int cur[MAX];//对于每个节点的,处理的当前弧。 int s,t,n;//s源点标号,t汇点标号,n节点总数 int mcut[2 * MAX],sz;//割的计数 void init(int n){ this->n = n; memset(head,-1,sizeof(head)); tot = sz = 0;// } void addedge(int from,int to, double cap,int num){ edges[tot] = edge(from,to,cap,0.0,num); next[tot] = head[from], head[from] = tot++; edges[tot] = edge(to,from,cap,0.0,num); next[tot] = head[to],head[to] = tot++; } void bfs(){ memset(vis,0,sizeof(vis)); front = tail = 0; d[t] = 0; vis[t] = true; que[tail++] = t; while(front < tail){ int u = que[front++]; for(int v = head[u]; v != -1; v = next[v]){ edge & e = edges[v^1]; if(dcmp(e.cap-e.flow) > 0 && !vis[e.from]){//对处于残余网络中的弧且没访问过的节点处理 d[e.from] = d[u] + 1; vis[e.from] = true; que[tail++] = e.from; } } } } double augment(){ int x = t; double a = INF; while(x != s){ edge& e = edges[pre[x]]; a = min(a,e.cap - e.flow); x = e.from; } for(int x = t;x != s;x = edges[pre[x]].from){ edges[pre[x]].flow += a; edges[pre[x]^1].flow -= a; } return a; } double maxflow(int s, int t){ this->s = s, this->t = t; memset(num,0,sizeof(num)); double flow = 0.0; bfs(); for(int i = 1; i <= n; ++i){//注意此处的下标问题 num[d[i]]++; cur[i] = head[i]; } int x = s; while(d[s] < n){ if(x == t){ flow += augment(); x = s; } bool ok = false; for(int v = cur[x]; v != -1; v = next[v]){ edge& e = edges[v]; if(dcmp(e.cap - e.flow) > 0 && d[x] == d[e.to] + 1){ ok = true; cur[x] = v; pre[x = e.to] = v; break; } } if(!ok){ int m = n - 1; for(int v = head[x]; v != -1; v = next[v]){ edge & e = edges[v]; if(dcmp(e.cap - e.flow) > 0) m = min(m,d[e.to]); } if(--num[d[x]] == 0) break; num[d[x]=m+1]++; cur[x] = head[x]; if(x != s) x = edges[pre[x]].from; } } return flow; } bool judge(double m){ init(N); double flow = 0.0; for(int i = 1 ; i <= M; ++i){ edge & e = a[i]; if(e.cap + EPS < m) mcut[sz++] = e.num,flow += e.cap - m; else addedge(e.from, e.to,e.cap - m,e.num); } return dcmp(flow + maxflow(1,N)) > 0; } void mincut(){ bfs(); for(int i = 0 ; i < tot; ++i){ edge & e = edges[i]; if(!vis[e.from] && vis[e.to] && e.cap > 0) mcut[sz++] = e.num; } sort(mcut,mcut + sz); } void print(){ printf("Graph:\n"); for(int i = 0 ; i < tot; ++i){ edge & e = edges[i]; printf("->%d c:%f p:%f\n",e.to,e.cap,e.flow); } } } solver; int main(void) { //freopen("in.txt","r",stdin); //freopen("out1.txt","w",stdout); int cas = 0; while(scanf("%d%d", &N,&M) != EOF){ for(int i = 1; i <= M; ++i){ scanf("%d%d%lf", &a[i].from,&a[i].to,&a[i].cap); a[i].num = i; } double lb = 0.0, ub = INF; while(fabs(lb - ub) > EPS){ double mid = (lb + ub) / 2.0; if(solver.judge(mid)) lb = mid; else ub = mid; } solver.mincut(); if(cas++) puts(""); //printf("%f\n",lb); printf("%d\n",solver.sz); for(int i = 0; i < solver.sz; ++i) printf("%d%c",solver.mcut[i], i == solver.sz -1?'\n':' '); } return 0; }
相关文章推荐
- zoj 2676 Network Wars(01分数规划+最小割)
- ZOJ 2676 Network Wars(01分数规划-二分+最小割)
- zoj 2676 Network Wars 【0-1分数规划 + 最小割】 【吃一堑长一智】
- ZOJ 2676 Network Wars ★(最小割算法介绍 && 01分数规划)
- ZOJ 2676 Network Wars ★(最小割算法介绍 && 01分数规划)
- zoj 2676 Network Wars 最小割+0-1分数规划
- zoj 2676 Network Wars(最小割,01分数规划)
- 【ZOJ】2676 Network Wars 01分数规划+最小割
- zoj 2676 Network Wars(01分数规划+网络流)
- zoj 2676 Network Wars(01分数规划+最大流)
- ZOJ 2676 Network Wars[01分数规划]
- 【ZOJ 2676】Network Wars 网络战争 网络流 01分数规划
- ZOJ-2676-Network Wars(01分数规划+最小割)
- ZOJ 2676 01分数规划 最小割
- HDU 2676 Network Wars 01分数规划,最小割 难度:4
- [ZJU 2676]Network Wars(分数规划+最小割)
- zoj 2676 Network Wars 0-1分数规划+最小割
- 【01分数规划】 ZOJ 2676 Network Wars
- zoj2676--Network Wars(0-1分数规划+最小割)
- zoj 2676 网络流+01分数规划