图论(网络流,分数规划):COGS 2047. [ZOJ2676]网络战争

2047. [ZOJ2676]网络战争

★★★   输入文件:networkwar.in   输出文件:networkwar.out   评测插件
时间限制:5 s  
内存限制:32 MB

【题目描述】

Byteland的网络是由n个服务器和m条光纤组成的,每条光纤连接了两个服务器并且可以双向输送信息。这个网络中有两个特殊的服务器,一个连接到了全球的网络,一个连接到了总统府,它们的编号分别是1和N.

最近一家叫做Max Traffic的公司决定控制几条网络中的光纤,以使他们能够掌握总统府的的上网记录。为了到达这个目的,他们需要使所有从1号服务器到N号服务器的数据都经过至少一条他们所掌握的线路。

为了把这个计划付诸于行动,他们需要从这些线路的拥有者手中购买线路,每条线路都有对应的花费。自从公司的主要业务部是间谍活动而是家用宽带以后,经理就希望尽可能少的花费和尽可能高的回报。因此我们要使购买线路的平均值最小。

如果我们购买了k条线路,花费了c元,我们希望找到使c/k最小的方案。

【输入格式】

多组数据,每组数据第一行是两个整数n和m(1<=n<=100,1<=m<=400),代表服务器的个数和线路数

之后的m行,每行三个整数a,b,c,分别代表了这条线路所连接的服务器和购买这条线路的花费,花费都是正数且不会超过10^7

没有自边,没有重边,保证任意两点都是连通的。

最后一行为两个0

【输出格式】

每组数据的第一行是一个整数k,代表购买多少条线路

之后k个整数,代表购买线路的编号,编号是它们在输入文件被给处的顺序

每组数据之间有一个空行

【样例输入】

6 8
1 2 3
1 3 2
2 4 2
2 5 2
3 4 2
3 5 2
5 6 3
4 6 3
4 5
1 2 2
1 3 2
2 3 1
2 4 2
3 4 2
0 0

【样例输出】

4
3 4 5 6

3
1 2 3

  可以看看2007胡博涛的论文。
  1 #include <iostream>
  2 #include <cstring>
  3 #include <cstdio>
  4 #include <queue>
  5 #include <cmath>
  6 using namespace std;
  7 const int maxn=10010;
  8 const int maxm=40010;
  9 const double eps=1e-7;
 10 const int INF=10000000;
 11 int n,m,e[maxm][3];
 12 int cnt,fir[maxn],to[maxm],nxt[maxm],ID[maxm];
 13 double cap[maxn];
 14 void addedge(int a,int b,double c,int id){
 15     nxt[++cnt]=fir[a];
 16     fir[a]=cnt;
 17     ID[cnt]=id;
 18     cap[cnt]=c;
 19     to[cnt]=b;
 20 }
 21
 22 queue<int>q;
 23 int dis[maxn];
 24 bool BFS(int s,int t){
 25     memset(dis,0,sizeof(dis));
 26     dis[t]=1;q.push(t);
 27     while(!q.empty()){
 28         int x=q.front();q.pop();
 29         for(int i=fir[x];i;i=nxt[i])
 30             if(!dis[to[i]]){
 31                 dis[to[i]]=dis[x]+1;
 32                 q.push(to[i]);
 33             }
 34     }
 35     return dis[s];
 36 }
 37
 38 int fron[maxn];
 39 int gap[maxn],path[maxn];
 40 double ISAP(int s,int t){
 41     if(!BFS(s,t))return 0;
 42     for(int i=s;i<=t;i++)++gap[dis[i]];
 43     for(int i=s;i<=t;i++)fron[i]=fir[i];
 44     int p=s;
 45     double f,ret=0;
 46     while(dis[s]<=t){
 47         if(p==t){
 48             f=INF;
 49             while(p!=s){
 50                 f=min(f,cap[path[p]]);
 51                 p=to[path[p]^1];
 52             }
 53             ret+=f;p=t;
 54             while(p!=s){
 55                 cap[path[p]]-=f;
 56                 cap[path[p]^1]+=f;
 57                 p=to[path[p]^1];
 58             }
 59         }
 60         int &ii=fron[p];
 61         for(;ii;ii=nxt[ii])
 62             if(cap[ii]>eps&&dis[p]==dis[to[ii]]+1)
 63                 break;
 64         if(ii)
 65             path[p=to[ii]]=ii;
 66         else{
 67             if(--gap[dis[p]]==0)break;
 68             int minn=t+1;
 69             for(int i=fir[p];i;i=nxt[i])
 70                 if(cap[i]>eps)minn=min(minn,dis[to[i]]);
 71             ++gap[dis[p]=minn+1];ii=fir[p];
 72             if(p!=s)p=to[path[p]^1];
 73         }
 74     }
 75     return ret;
 76 }
 77
 78 int ch[maxm],ans;
 79 void Init(){
 80     memset(fir,0,sizeof(fir));
 81     memset(gap,0,sizeof(gap));
 82     memset(ch,0,sizeof(ch));
 83     cnt=1;
 84 }
 85
 86
 87 double Solve(double lam){
 88     Init();
 89     double ret=0.0;
 90     for(int i=1;i<=m;i++){
 91         if(e[i][2]-lam<-eps){
 92             ret+=e[i][2]-lam;
 93             ch[i]=1;
 94         }
 95         else{
 96             addedge(e[i][0],e[i][1],e[i][2]-lam,i);
 97             addedge(e[i][1],e[i][0],e[i][2]-lam,i);
 98         }
 99     }
100     ret+=ISAP(1,n);
101     for(int i=2;i<=cnt;i++)
102         if(fabs(cap[i])<eps&&ID[i])ch[ID[i]]=1;
103     return ret;
104 }
105
106 int main(){
107 #ifndef ONLINE_JUDGE
108     freopen("networkwar.in","r",stdin);
109     freopen("networkwar.out","w",stdout);
110 #endif
111     while(true){
112         scanf("%d%d",&n,&m);
113         if(!n&&!m)break;
114         for(int i=1;i<=m;i++)
115             for(int j=0;j<=2;j++)
116                 scanf("%d",&e[i][j]);
117         double lo=eps,hi=INF,lam;
118         for(int t=1;t<=30;t++){
119             lam=(lo+hi)/2;
120             if(Solve(lam)>eps)
121                 lo=lam;
122             else
123                 hi=lam;
124             if(hi-lo<eps)break;
125         }
126         ans=0;
127         for(int i=1;i<=m;i++)
128             if(ch[i])ans+=1;
129         printf("%d\n",ans);
130         for(int i=1;i<=m;i++)
131             if(ch[i])printf("%d ",i);
132         printf("\n\n");
133     }
134     return 0;
135 }
时间: 2024-09-29 21:54:48

图论(网络流,分数规划):COGS 2047. [ZOJ2676]网络战争的相关文章

bzoj 3232 圈地游戏——0/1分数规划(或网络流)

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3232 当然是0/1分数规划.但加的东西和减的东西不在一起,怎么办? 考虑把它们合在一起.因为边围成的形状像一个环,所以把格子的贡献也放到边上,然后正常判环. 放到边上的方法就是:比如竖着的边,可以在每一行上维护该行格子值前缀和,然后指定那个围成的形状是,比如,逆时针的,那么向上的边就加上到它为止的前缀值,向下的边就减去到它为止的前缀值,然后就能判环了! 这样一定只有一个环.但多个环答案不会

zoj2676--Network Wars(0-1分数规划+最小割)

zoj2676:题目链接 题目大意:有一个n个点的网络,其中有m条光缆(所有的点都被连接,任意两个点之间最多有一条,不存在连接自身的),每条光缆有一定的价值,网络中1为起点,n为终点,现在要求找出一些光缆能分割开1到n,使它们不能相互通信,并且要求花费的和除以光缆数的值最小.输出选择的光缆的编号. 从问题中可以看出一定是0-1分数规划的题目,假设选出光缆的集合M,M为原图的一个割,光缆si∈M,价值为ci,数量k = 1 ,可以推出g(x) = min( ∑c - x*∑k ),因为si是割中的

【BZOJ3232】圈地游戏 分数规划+最小割

[BZOJ3232]圈地游戏 Description DZY家的后院有一块地,由N行M列的方格组成,格子内种的菜有一定的价值,并且每一条单位长度的格线有一定的费用. DZY喜欢在地里散步.他总是从任意一个格点出发,沿着格线行走直到回到出发点,且在行走途中不允许与已走过的路线有任何相交或触碰(出发点除外).记这条封闭路线内部的格子总价值为V,路线上的费用总和为C,DZY想知道V/C的最大值是多少. Input 第一行为两个正整数n,m. 接下来n行,每行m个非负整数,表示对应格子的价值. 接下来n

编程之美第一篇 01分数规划

01分数规划 01分数规划问题其实就是解决单价之类的问题,假设给你n个物品,让你找出选k个物品的最大单价:例如南阳oj:Yougth的最大化:解决这类问题可以用二分查找,这类问题跟二分极大化最小值,极小化最大值有一些相似的地方,均是从结果出发,来进行二分查找:例如上面南阳那道题,可以转化一下: 由于v/w=单价:所以v=w*单价:即v-w*单价=0:有了这个关系,我们马上可以想到二分来查找这个值: 那么我们可以定义一个count数组来记录v-w*单价的值:由于选k个只需要把count从大到小排下

zoj 2676 Network Wars(最小割,01分数规划)

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2676 大致题意:给出一个带权无向图,每条边有一个边权wi,求将S和T分开的一个割边集C,使得该割边集的平均边权最小,即最小化∑wi / |C| . 详见amber关于最小割模型的论文 思路:amber论文中详细讲解了如何转化成函数及建图,值得注意的是当边被重新赋权后,对于wi < 0 的边权,该边必然在最小割中,不必再建边,直接加入最大流中即可,因为求最小割时边权都为正值

[转]01分数规划算法 ACM 二分 Dinkelbach 最优比率生成树 最优比率环

01分数规划 前置技能 二分思想最短路算法一些数学脑细胞?问题模型1 基本01分数规划问题 给定nn个二元组(valuei,costi)(valuei,costi),valueivaluei是选择此二元组获得的价值(非负),costicosti是选择此二元组付出的代价(非负),设xi(xi∈{0,1})xi(xi∈{0,1})代表第ii个二元组的选与不选,最大(小)化下式 maximize(or minimize)   r=∑valuei?xi∑costi?ximaximize(or minim

2019.4.9 一题——概率期望+0/1分数规划+最大权闭合子图

没注意 “第 x 条边和第 y 条边的起点是相同的” 的限制.没想出来. 有这个限制,可以考虑每个点分别计算.令 \( f[i] \) 表示从 i 出发的最大边数期望,那么先把拓扑序在自己之后的点的 \( f[ ] \) 算出来,然后考虑自己这个点的出边怎么做能使自己的 \( f[ ] \) 最大. \( f[i]=\frac{ \sum f[j]+1 }{ d } \) ,其中 d 是保留下来的边数, j 是保留边指向的点. 如果把 \( f[ ]+1 \) 看做收益, 1 看做代价,那么这个

01分数规划模板

/* 01分数规划模板(Dinkelbach) 01分数规划就是把 sum(a)/sum(b)转换成 f(x)=sum(a)-ans*sum(b); 当f(x)取到0时,ans取到了最大(小)值 poj 2976 两个长度为n的数组a,b 可以除去m个,怎样选择才能使剩下的 sum(a)/sum(b)的百分数最大 */ int n,m; struct Node{ int a,b; double v; ///用于排序筛选较大的值(题目要求极大值 bool operator<(const Node&am

poj3621 Sightseeing Cows --- 01分数规划

典型的求最优比例环问题 参考资料: http://blog.csdn.net/hhaile/article/details/8883652 此题中,给出每个点和每条边的权值,求一个环使 ans=∑点权/∑边权 最大. 因为题目要求一个环,而且必然是首尾相接的一个我们理解的纯粹的环,不可能是其他样子的环, 所以我们可以把一条边和指向的点看做整体处理. 上面方程可以化为:ans×e[i]-p[i]=0 以它为边权二分答案,spfa求负环,有负环则该ans可行,增大下界. 若一直不可行,则无解. #i