Description
Input
Output
Sample Input
4 5
1 2 5
2 3 5
3 1 5
2 4 3
4 1 3
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 }