题目链接:http://poj.org/problem?id=3621
在一个有向图中选一个环,使得环上的点权和除以边权和最大。求这个比值。
经典的分数规划问题,我认为这两篇题解写得非常清楚,能够參考一下http://blog.csdn.net/gengmingrui/article/details/47443705,http://blog.csdn.net/wall_f/article/details/8221807
个人认为01分数规划差点儿都是二分或者迭代比值,从而找到一个最优解,使得原来的函数值等于0
#include<cstdio> #include<cstring> #include<queue> #define eps 1e-3 #define MAXN 1010 using namespace std; struct T { int v; int w; int next; }edge[5005]; int cnt,head[MAXN]; void add_edge(int u,int v,int w) { edge[cnt].v = v; edge[cnt].w = w; edge[cnt].next = head[u]; head[u] = cnt++; } int n,m; int w[MAXN]; double dis[MAXN]; bool inque[MAXN]; int vis[MAXN]; bool SPFA(double R)//SPFA推断负权环 { queue<int> myque; memset(inque,0,sizeof inque); memset(vis,0,sizeof vis); for(int i = 1; i <= n; i++) dis[i] = 1e15; myque.push(1); dis[1] = 0; inque[1] = 1; vis[1]++; while(!myque.empty()) { int u = myque.front(); myque.pop(); inque[u] = 0; for(int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].v; int y = edge[i].w; if(dis[u] + R*y - w[u] < dis[v]) { dis[v] = dis[u] + R*y - w[u]; if(!inque[v]) { myque.push(v); inque[v] = 1; vis[v]++; if(vis[v] > n) return 1; } } } } return 0; } int main() { memset(head,-1,sizeof head); scanf("%d%d",&n,&m); for(int i = 1; i <= n; i++) scanf("%d",&w[i]); for(int i = 1; i <= m; i++) { int a,b,c; scanf("%d%d%d",&a,&b,&c); add_edge(a,b,c); } double l = 0,r = 10000,mid; while(r - l > eps) { mid = (l+r)/2; if(SPFA(mid)) l = mid;//因为我们是把权值取反了的。因此题解中的R过大变成了R过小 else r = mid; } printf("%.2lf ",l); return 0; }