BZOJ1486 [HNOI2009]最小圈

Description

Input

Output

Sample Input

4 5
1 2 5
2 3 5
3 1 5
2 4 3
4 1 3

Sample Output

3.66666667
 
 
正解:SPFA+二分答案
解题报告:
  分数规划,具体我不是很会证,传送门:http://blog.csdn.net/fzhvampire/article/details/49454627
  大概意会一下还是可以理解的。
  首先对于这种问题我觉得有一点通项公式的味道,像上次做的黑边、白边的题目,也是同样的。因为我们想得到某个权值,需要对边进行操作。
  比如说这道题,要求最小圈平均权值。显然如果我们先二分答案变成判定性问题会好做一些。二分一个答案ans,将每条边都减去ans,然后SPFA找负权环,如果找到了就说明这个ans可以成为最小圈平均权值,但是还不够优。所以我们需要不断试探,直到精度满足要求。至于判环,用DFS版的SPFA应该要比BFS版的快很多。
  注意一下精度问题,要求8位,那么必须要二分到9位,第一次就因为这个WA了一次。
  常见思路:二分一个答案,每条边减去,再进行判定与check
 
 
  
 1 //It is made by jump~
 2 #include <iostream>
 3 #include <cstdlib>
 4 #include <cstring>
 5 #include <cstdio>
 6 #include <cmath>
 7 #include <algorithm>
 8 #include <ctime>
 9 #include <vector>
10 #include <queue>
11 #include <map>
12 #include <set>
13 #ifdef WIN32   
14 #define OT "%I64d"
15 #else
16 #define OT "%lld"
17 #endif
18 using namespace std;
19 typedef long long LL;
20 const int MAXN = 3011;
21 const int MAXM = 20011;
22 const double eps = 0.000000001;
23 int n,m,ecnt;
24 int first[MAXN],u[MAXM],v[MAXM];
25 double w[MAXM],dis[MAXN];
26 double l,r,mid,ans;
27 bool ok;
28 bool vis[MAXN];
29 struct edge{
30     int next,to;
31     double w;
32 }e[MAXM];
33 
34 inline int getint()
35 {
36        int w=0,q=0;
37        char c=getchar();
38        while((c<'0' || c>'9') && c!='-') c=getchar();
39        if (c=='-')  q=1, c=getchar();
40        while (c>='0' && c<='9') w=w*10+c-'0', c=getchar();
41        return q ? -w : w;
42 }
43 
44 inline void link(int x,int y,double z){ e[++ecnt].next=first[x]; first[x]=ecnt; e[ecnt].to=y; e[ecnt].w=z;   }
45 
46 inline void SPFA(int x){//DFS版SPFA找负权环,只有碰到负边才走
47     vis[x]=1;
48     for(int i=first[x];i;i=e[i].next){
49     int v=e[i].to;
50     if(dis[v]>dis[x]+e[i].w) {
51         if(vis[v]) { ok=true; return ; }
52         dis[v]=dis[x]+e[i].w; SPFA(v);
53         if(ok) return ;
54     }
55     }
56     vis[x]=0;//退出时记得清空标记
57 }
58 
59 inline bool check(double val){
60     memset(first,0,sizeof(first)); ecnt=0;
61     memset(vis,0,sizeof(vis));
62     memset(dis,0,sizeof(dis));
63     ok=false; for(int i=1;i<=m;i++) link(u[i],v[i],w[i]-val);
64     for(int i=1;i<=n;i++) {
65     SPFA(i);//DFS版SPFA
66     if(ok) return true;
67     }
68     return false;
69 }
70 
71 inline void work(){
72     n=getint(); m=getint();
73     for(int i=1;i<=m;i++) u[i]=getint(),v[i]=getint(),scanf("%lf",&w[i]);
74 
75     l=-10000000; r=10000000;
76     while(r-l>eps) {
77     mid=(l+r)/2.0;
78     if(check(mid)) ans=mid,r=mid;//已经产生负权环
79     else l=mid;
80     }
81     printf("%.8lf",ans);
82 }
83 
84 int main()
85 {
86   work();
87   return 0;
88 }
原文地址:https://www.cnblogs.com/ljh2000-jump/p/5758362.html