http://poj.org/problem?id=3621 /* 分析: 题目的意思是:求一个环的{点权和}除以{边权和},使得那个环在所有环中{点权和}除以{边权和}最大。 令在一个环里,点权为v[i],对应的边权为e[i], 即要求:∑(i=1,n)v[i]/∑(i=1,n)e[i]最大的环(n为环的点数), 设题目答案为ans, 即对于所有的环都有 ∑(i=1,n)(v[i])/∑(i=1,n)(e[i])<=ans 变形得ans* ∑(i=1,n)(e[i])>=∑(i=1,n)(v[i]) 再得 ∑(i=1,n)(ans*e[i]-v[i]) >=0 稍分析一下,就有: 当k<ans时,就存在至少一个环∑(i=1,n)(k*e[i]-v[i])<0,即有负权回路(边权为k*e[i]-v[i]); 当k>=ans时,就对于所有的环∑(i=1,n)(k*e[i]-v[i])>=0,即没有负权回路。 然后我们就可以使新的边权为k*e[i]-v[i],用spfa来判断付权回路,二分ans。 */ #include<iostream> #include<queue> #include<vector> #include<cmath> using namespace std; const int MAXN = 1001; const double inf = 1000000000.0; struct edge { int v; int w; }; vector<edge> graph[MAXN]; double d[MAXN];//d[i]表示从源点到点i的距离 bool visit[MAXN];//标记是否在队里 int fun[MAXN];//表示牛的欢乐值 int cnt[MAXN];//用来判断是否存在负权路径 int n, m; int src;//标记源点 bool spfa(double mid)//如果返回值为1,表示存在负权路径;如果不是,表示不存在负权路径 { int i, j; queue<int> q; for(i=1; i<=n; i++)//初始化d数组 { d[i] = inf; } memset(visit, 0, sizeof(visit)); memset(cnt, 0, sizeof(cnt)); d[src] = 0;//源点入队 visit[src] = true; cnt[src]++; q.push(src); while(!q.empty()) { int frontv = q.front(); q.pop(); visit[frontv] = false; for(j=0; j<graph[frontv].size(); j++) { int tempv = graph[frontv][j].v; int tempw = graph[frontv][j].w; if(d[tempv] > d[frontv] + tempw*mid - fun[tempv])//权值time*ans - fun[v] { d[tempv] = d[frontv] + tempw*mid - fun[tempv]; if(!visit[tempv])//不在队中 { visit[tempv] = true; q.push(tempv); cnt[tempv]++; if(cnt[tempv] >= n)//存在负权路径 return true; } } } } return false;//不存在负权路径 } int main() { // freopen("in.txt","r",stdin); int i; int u, v, w; double left, right, mid, ans; edge tempedge; while(scanf("%d%d", &n, &m) != EOF) { for(i=1; i<=n; i++) { graph[i].clear(); scanf("%d", &fun[i]); } for(i=1; i<=m; i++) { scanf("%d %d %d", &u, &v, &w); tempedge.v = v; tempedge.w = w; graph[u].push_back(tempedge); } left = 0; right = 1000; //1<=Ti<=1000,1<=Fi<=1000,回路中包含一个顶点时最大值为1000,二个顶点时最大值是1000,依次递推,最大值为1000 src = 1; while(1) { ans = mid; mid = (left + right)/2; if(fabs(ans-mid)<1e-6) break; if(spfa(mid))//存在负权路径 { left = mid; } else//不存在负权路径 { right = mid; } } printf("%.2lf/n", ans); } return 0; }