链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=34650
【思路】
二分+SPFA。
二分平均值mid,如果有平均值小于mid的情况我们就缩小猜测值否则增大猜测值。如何判定?如果有平均值小于mid 则有:w1-mid+w2-mid+w3-mid+…<0 即将各条边权减mid后图中存在负圈,SPFA判负圈即可。
需要注意把int修改为double
【代码】
1 #include<cstdio> 2 #include<queue> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 7 const int maxn = 100+10; 8 const double INF=1e10; 9 struct Edge{ 10 int v,next; 11 double w; 12 }e[maxn*maxn]; 13 int en,front[maxn]; 14 15 int n,m; 16 17 inline void AddEdge(int u,int v,double w) { 18 en++; e[en].v=v; e[en].w=w; e[en].next=front[u]; front[u]=en; 19 } 20 21 bool SPFA_NC() { 22 int inq[maxn],cnt[maxn]; 23 double d[maxn]; 24 queue<int> q; 25 memset(cnt,0,sizeof(cnt)); 26 memset(inq,0,sizeof(inq)); 27 //添加一个超级源节点 28 for(int s=1;s<=n;s++) 29 { 30 d[s]=0; inq[s]=1; q.push(s); 31 } 32 while(!q.empty()) { 33 int u=q.front(); q.pop(); inq[u]=0; 34 for(int i=front[u];i>=0;i=e[i].next) { 35 int v=e[i].v; double w=e[i].w; 36 if(d[v]>d[u]+w) { 37 d[v]=d[u]+w; 38 if(!inq[v]) { 39 inq[v]=1; 40 q.push(v); 41 if(++cnt[v]>n+1) return true; 42 } 43 } 44 } 45 } 46 return false; 47 } 48 49 inline void init() { 50 en=0; 51 memset(front,-1,sizeof(front)); 52 } 53 54 bool can(double x) { 55 for(int i=1;i<=en;i++) e[i].w-=x; 56 bool ans=SPFA_NC(); 57 for(int i=1;i<=en;i++) e[i].w+=x; 58 return ans; 59 } 60 61 int main() { 62 int T; 63 scanf("%d",&T); 64 for(int kase=1;kase<=T;kase++) { 65 init(); 66 scanf("%d%d",&n,&m); 67 double L=0,R=0; 68 int u,v; double w; 69 for(int i=0;i<m;i++) { 70 scanf("%d%d%lf",&u,&v,&w); 71 AddEdge(u,v,w); 72 if(w>R) R=w; 73 } 74 printf("Case #%d: ",kase); 75 if(!can(R+1)) printf("No cycle found.\n"); 76 else 77 { 78 while(R-L>1e-3) { 79 double M=L+(R-L)/2; 80 if(can(M)) R=M; //存在平均值小于mid的回路 则缩小猜测值 81 else L=M; 82 } 83 printf("%.2lf\n",L); 84 } 85 } 86 return 0; 87 }
时间: 2024-10-19 12:37:57