poj 3621 Sightseeing Cows (最优比率环)

http://poj.org/problem?id=3621

题意:

给定 一些 点的 欢乐值 ,和一些点的距离 ,求 是否存在一个环使得 ,欢乐值 /走的总距离,   最大 ;

题解:整数规划 问题。 

首先的一个结论就是,不会存在环套环的问题,即最优的方案一定是一个单独的环,而不是大环套着小环的形式。这个的证明其实非常的简单,大家可以自己想一下 (提示,将大环上的收益和记为x1,花费为y1,小环上的为x2,y2。重叠部分的花费为S。表示出来分类讨论即可)。有了这个结论,我们就可以将花费和 收益都转移到边上来了,因为答案最终一定是一个环,所以我们将每一条边的收益规定为其终点的收益,这样一个环上所有的花费和收益都能够被正确的统计。

 

解决了蛋疼的问题之后,就是01分数规划的部分了,我们只需要计算出D数组后找找有没有正权环即可,用spfa(单源最短路径) 判断即可。

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<cmath>
  4 #include<iostream>
  5 #include<algorithm>
  6 #include<set>
  7 #include<map>
  8 #include<queue>
  9 #include<vector>
 10 #include<string>
 11 #define Min(a,b) a<b?a:b
 12 #define Max(a,b) a>b?a:b
 13 #define CL(a,num) memset(a,num,sizeof(a));
 14 #define eps  1e-6
 15 #define inf 10001000
 16 
 17 #define ll   __int64
 18 
 19 #define  read()  freopen("data.txt","r",stdin) ;
 20 const double pi  = acos(-1.0);
 21 const int maxn = 1024;
 22 
 23 using namespace std;
 24 struct node
 25 {
 26     int u;
 27     int v;
 28     int len ;
 29     int next ;
 30 }p[maxn*5] ;
 31 int n , m ;
 32 int cnt , head[maxn],num[maxn],a[maxn];
 33 double dis[maxn];
 34 int vis[maxn] ;
 35 void add(int u,int v,int len )
 36 {
 37     p[cnt].v = v;
 38     p[cnt].len = len;
 39     p[cnt].next = head[u] ;
 40     head[u] = cnt++ ;
 41 }
 42 
 43 queue<int>que;
 44 bool spfa(double mid)
 45 {
 46     int  i ;
 47     while(!que.empty())que.pop() ;
 48     
 49     for(i = 1 ; i <= n;i++)
 50     {
 51         dis[i] = -inf;
 52 
 53 
 54     }
 55 
 56     que.push(1) ;
 57     
 58     dis[1] = 0;
 59     
 60     CL(vis,0) ;
 61     
 62     vis[1] = 1;
 63 
 64     CL(num,0) ;
 65 
 66 
 67 
 68     while(!que.empty())
 69     {
 70         int u = que.front() ;que.pop() ;
 71         vis[u] = 0 ;
 72         for(i = head[u];i !=-1 ;i = p[i].next)
 73         {
 74             int v = p[i].v ;
 75             int len = p[i].len ;
 76             double t = a[v] - mid * len ;
 77             if(dis[u]  + t >  dis[v])
 78             {
 79                 dis[v] = t + dis[u];
 80                num[v] ++;
 81                 if(!vis[v])
 82                 {
 83                     que.push(v) ;
 84                     vis[v] = 1 ;
 85 
 86 
 87                 }
 88                 if(num[v] >= n) return true ;
 89 
 90 
 91 
 92             }
 93         }
 94 
 95     }
 96     return false ;
 97 }
 98 int main()
 99 {
100     int i ;
101     int x,y;
102     int d;
103     //read() ;
104     while(scanf("%d%d",&n,&m)!=EOF)
105     {
106         cnt =  0 ;
107         CL(head,-1) ;
108         for(i = 1  ;i <=  n;i++)
109           scanf("%d",&a[i]) ;
110         for(i = 0  ; i< m;i++)
111         {
112             scanf("%d%d%d",&x,&y,&d) ;
113             add(x,y,d);
114 
115         }
116         double  l = 0, r = 2500,mid;
117         double ans = -1;
118         while(r - l >= eps)
119         {
120             mid = (l + r)/2.0 ;
121             if(spfa(mid))
122             {
123                 ans = mid;
124                 l = mid ;
125             }
126             else r = mid ;
127         }
128 
129         if(ans < 0)printf("0\n");//判断是否有环
130         else
131         printf("%.2lf\n",ans) ;
132 
133 
134     }
135 }

 


 


 

posted @ 2012-10-06 15:35  Szz  阅读(414)  评论(0编辑  收藏  举报