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