题意:在给定的图中找一个环,使得 sum(点权)/sum(边权) 最大。
思路:
参考链接------>http://www.cnblogs.com/jackge/archive/2013/05/11/3072490.html
此题是对01分数规划的应用,那么首先明白01分数规划的思想.
01整数规划问题就是求解方程(a1*x1+a2*x2+..+an*xn)/(b1*x1+b2*x2+..+bn*xn)的最小值/最大值问题。其中xi = 0或1(i=1,2...n)
对于此类问题我们可以通过二分来求解很接近答案的近似值。我们可以先令:
(a1*x1+a2*x2+..+an*xn)/(b1*x1+b2*x2+..+bn*xn)=L,则我们可以将此式转换为:x1*(a1-b1*L)+x2*(a2-b2*L)+...xn*(an-bn*L)=0,我们先定义一个估计值val,如果这个值使得上面的式子小于0我们就可以知道val>L,如果上式等于0,则val = L;如果大于0,则val<L,显然我们可以采用二分的思想求解次问题。
对于此题,设happy[u]为点u的欢乐值,w[u][v]为u-->v的边权值。要求的是happy[1]+happy[2]+...+happy[n] / w[1][2]+...+w[n-1][n] = ans,设ans就是所求的最大值。则移项,ans*w[u][v] - happy[v] = 0 .我们重新构造一幅图,使得边权为happy[v] - ans*w[u][v]。用SPFA算法,二分枚举ans,判断是否存在负权回路,若存在,说明ans偏小了,则增大ans,若不存在,则减小ans。
开始把二分的精度 写的10e-3wa了一发= =,改成10e-7顺利AC( ⊙o⊙ )哇
从来没接触过这类题额。。。。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#define eps 10e-7
#define maxm 5010
#define maxn 1010
using namespace std;
const double INF = 1000000000;
struct Edge
{
int to,val,next;
}edge[maxm];
int head[maxn],cnt,n,c[maxn],a[maxn];
double dis[maxn];
bool inq[maxn];
queue<int> q;
void add(int x,int y,int z)
{
edge[cnt].to = y;
edge[cnt].val = z;
edge[cnt].next = head[x];
head[x] = cnt++;
}
bool spfa(double l)
{
while(!q.empty())
q.pop();
for(int i=2;i<=n;i++)
{
dis[i] = INF;
inq[i] = false;
c[i] = 0;
}
dis[1] = 0;
q.push(1);
c[1] = 1;
inq[1] = true;
while(!q.empty())
{
int op = q.front();
inq[op] = false;
q.pop();
for(int i=head[op];i!=-1;i = edge[i].next)
{
int t = edge[i].to;
double d = edge[i].val*l-a[t];
if(dis[t] > dis[op]+d)
{
dis[t] = dis[op]+d;
if(!inq[t])
{
q.push(t);
c[t]++;
inq[t] = true;
if(c[t]>=n)
return false;
}
}
}
}
return true;
}
int main()
{
int m,u,v,w;
while(scanf("%d%d",&n,&m)!=EOF)
{
cnt = 0;
memset(head,-1,sizeof(head));
memset(edge,0,sizeof(edge));
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
}
double l = 0,r = 10000,mid,ans;
while(r-l>eps)
{
mid = (l+r)/2;
if(!spfa(mid))
{
ans = mid;
l = mid;
}
else r = mid;
}
printf("%.2f\n",ans);
}
return 0;
}