图论(网络流,分数规划):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
",ans);
130         for(int i=1;i<=m;i++)
131             if(ch[i])printf("%d ",i);
132         printf("

");        
133     }
134     return 0;    
135 }
原文地址:https://www.cnblogs.com/TenderRun/p/5639189.html