典型的求最优比例环问题
参考资料:
http://blog.csdn.net/hhaile/article/details/8883652
此题中,给出每个点和每条边的权值,求一个环使 ans=∑点权/∑边权 最大。
因为题目要求一个环,而且必然是首尾相接的一个我们理解的纯粹的环,不可能是其他样子的环,
所以我们可以把一条边和指向的点看做整体处理。
上面方程可以化为:ans×e[i]-p[i]=0
以它为边权二分答案,spfa求负环,有负环则该ans可行,增大下界。
若一直不可行,则无解。
#include<cstdio> #include<cstring> #include<vector> #include<queue> #include<iostream> #include<algorithm> #include<cmath> #define inf 0x3f3f3f3f using namespace std; #define N 1010 #define M 5010 struct node { int next,v,w; }e[M]; int n,m,h,head[N],p[N],inq[N],outq[N]; double d[N]; void addedge(int a,int b,int c) { e[h].v=b; e[h].w=c; e[h].next=head[a]; head[a]=h++; } bool spfa(int s,double ans) { int i,cnt=0; for(i=0;i<=n;i++) d[i]=2000000000; memset(inq,0,sizeof inq); memset(outq,0,sizeof outq); d[s]=0; inq[s]=1; queue<int> q; q.push(s); while(!q.empty()) { int x=q.front(); q.pop(); inq[x]=0; outq[x]++; cnt++; if(outq[x]>n) return 0; if(cnt>(n+m)<<1) return 0; for(i=head[x];i!=-1;i=e[i].next) { int v=e[i].v; if(d[v]>d[x]+ans*e[i].w-p[v]) { d[v]=d[x]+ans*e[i].w-p[v]; if(!inq[v]) q.push(v); } } } return 1; } int main() { int a,b,c,i; double le,ri,mid; while(~scanf("%d%d",&n,&m)) { memset(head,-1,sizeof head); h=0; for(i=1;i<=n;i++) scanf("%d",&p[i]); for(i=0;i<m;i++) { scanf("%d%d%d",&a,&b,&c); addedge(a,b,c); } le=0;ri=1010; double ans=0; while(ri-le>1e-5) { mid=(le+ri)/2.0; if(spfa(1,mid)) { ri=mid; } else { ans=mid; le=mid; } } printf("%.2lf\n",ans);//G++要用%f才能A } return 0; }
poj3621 Sightseeing Cows --- 01分数规划,布布扣,bubuko.com
时间: 2024-10-08 10:59:25