题目链接:
https://vjudge.net/problem/UVA-11090
题意:
给你一个有向图,问你定义一个环的平均值为这个环上所有边的平均值,问你最小的环的平均值是多少
题解:
二分答案:若当前的二分值是mid,让所有的边都减去这个值,如果此时图中出现负环,则说明有环的平均值比这个更小
假设一个包含k条边的回路,回路上各条边的权值为w1,w2……wk,那么平均值小于mid意味着 w1+w2+……wk< k* mid即:
(w1-mid)+(w2-mid)+……(wk-mid)<0
有负环,当前平均值就大了
注意图可能不连通,每个没访问过得点都spfa判一遍
代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 #define MS(a) memset(a,0,sizeof(a)) 5 #define MP make_pair 6 #define PB push_back 7 const int INF = 0x3f3f3f3f; 8 const ll INFLL = 0x3f3f3f3f3f3f3f3fLL; 9 inline ll read(){ 10 ll x=0,f=1;char ch=getchar(); 11 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 12 while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} 13 return x*f; 14 } 15 ////////////////////////////////////////////////////////////////////////// 16 const int maxn = 50+10; 17 double eps = 1e-6; 18 19 int n,m; 20 21 vector<pair<int,double> > G[maxn]; 22 int vis[maxn],inq[maxn],cnt[maxn]; 23 double d[maxn]; 24 25 bool spfa(int u){ 26 MS(inq);MS(cnt); 27 for(int i=0; i<=n; i++) d[i] = INF; 28 queue<int> q; 29 q.push(u),inq[u]=1,d[u]=0; 30 while(!q.empty()){ 31 int now = q.front(); q.pop(); inq[now] = 0; 32 vis[now] = 1; 33 for(int i=0; i<(int)G[now].size(); i++){ 34 int v = G[now][i].first; double w = G[now][i].second; 35 if(d[v] > d[now]+w){ 36 d[v] = d[now]+w; 37 if(inq[v]) continue; 38 inq[v] = 1; 39 q.push(v); 40 cnt[v]++; 41 if(cnt[v] > n) return true; 42 } 43 } 44 } 45 return false; 46 } 47 48 bool check(double x){ 49 for(int i=1; i<=n; i++) 50 for(int j=0; j<(int)G[i].size(); j++) 51 G[i][j].second -= x; // 让所有的边都减去mid,如果此时图中出现负环,则说明有环的平均值比这个更小 52 MS(vis); 53 bool flag; 54 for(int i=1; i<=n; i++){ 55 if(!vis[i]) // 图可能不连通,每个没访问过得点都判一遍 56 flag = spfa(i); 57 if(flag) break; 58 } 59 60 for(int i=1; i<=n; i++) 61 for(int j=0; j<(int)G[i].size(); j++) 62 G[i][j].second += x; 63 64 return flag; // flag为true 就是有负环,当前平均值就大了 65 } 66 67 68 int main(){ 69 int T = read(); 70 for(int cas=1; cas<=T; cas++){ 71 for (int i = 0; i <= n; i++)G[i].clear(); 72 scanf("%d%d",&n,&m); 73 for(int i=1; i<=m; i++){ 74 int u,v; double w; 75 scanf("%d%d%lf",&u,&v,&w); 76 G[u].push_back(MP(v,w)); 77 } 78 79 double L=0,R=1e7,ans=1e7; 80 while((R-L)>eps){ 81 double mid = (L+R)/2; 82 if(check(mid)) ans=mid,R=mid-eps; 83 else L=mid+eps; 84 } 85 if(abs(ans-1e7)<eps) printf("Case #%d: No cycle found. ",cas); 86 else printf("Case #%d: %.2lf ",cas,ans); 87 } 88 89 return 0; 90 }