POJ 3621 01分数规划

题意:

给出一个有向图,问求一个回路,使得回路上的点权之和/边权之和最大。

 

题解:

01分数规划,简单构造,将点权转移到边权上~因为一个环上的点和边的数量是相等的~

设i,j之间初始边权为w[i][j],修改后的边权为g[i][j],则g[i][j]=w[i][j]*mid+val[i]

spfa判负环即可~

01分数规划详见:http://www.cnblogs.com/proverbs/archive/2013/01/09/2853725.html

 

代码包含bfs版spfa和dfs版spfa两种版本

dfs版spfa真是快,16ms,在c++里耗时排第一,嘿嘿~

 

View Code
  1 #include <iostream>
  2 #include <cstring>
  3 #include <cstdlib>
  4 #include <cstdio>
  5 #include <algorithm>
  6 #include <cmath>
  7 
  8 #define N 1100
  9 #define M 1000100
 10 
 11 using namespace std;
 12 
 13 int a[M],b[M];
 14 int head[N],next[M],to[M];
 15 int q[M*5],im[N];
 16 int vis[N];
 17 int n,cnt,m,st;
 18 double l,r,mid,c[M],dis[N],len[M],val[N];
 19 
 20 inline void add(int u,int v,double w)
 21 {
 22     to[cnt]=v; len[cnt]=w; next[cnt]=head[u]; head[u]=cnt++;
 23 }
 24 
 25 inline void read()
 26 {
 27     memset(head,-1,sizeof head); cnt=0;
 28     for(int i=1;i<=n;i++) scanf("%lf",&val[i]);
 29     for(int i=1;i<=m;i++)
 30     {
 31         scanf("%d%d%lf",&a[i],&b[i],&c[i]);
 32         add(a[i],b[i],c[i]);
 33     }
 34 }
 35 /*queue版spfa 
 36 inline bool spfa()
 37 {
 38     memset(im,0,sizeof im);
 39     int h=1,t=1,sta;
 40     for(int i=1;i<=n;i++)
 41     {
 42         q[t++]=i;
 43         dis[i]=0.0;
 44         vis[i]=true;
 45         im[i]++;
 46     }
 47     while(h!=t)
 48     {
 49         sta=q[h++]; vis[sta]=false;
 50         for(int i=head[sta];~i;i=next[i])
 51             if(dis[to[i]]>dis[sta]+len[i]*mid-val[sta])
 52             {
 53                 dis[to[i]]=dis[sta]+len[i]*mid-val[sta];
 54                 if(!vis[to[i]])
 55                 {
 56                     vis[to[i]]=true;
 57                     q[t++]=to[i];
 58                     if(++im[to[i]]>n) return true;
 59                 }
 60             }
 61     }
 62     return false;
 63 }
 64 */
 65 
 66 inline bool dfs(int u)
 67 {
 68     vis[u]=st;
 69     for(int i=head[u];~i;i=next[i])
 70         if(dis[to[i]]>dis[u]+len[i]*mid-val[u])
 71         {
 72             dis[to[i]]=dis[u]+len[i]*mid-val[u];
 73             if(vis[to[i]]==st) return true;
 74             else if(dfs(to[i])) return true;
 75         }
 76     vis[u]=0;
 77     return false;
 78 }
 79 //dfs-spfa找负环 
 80 inline bool spfa()
 81 {
 82     memset(vis,0,sizeof vis);
 83     for(st=1;st<=n;st++)
 84         if(dfs(st)) return true;
 85     return false;
 86 }
 87 
 88 inline void go()
 89 {
 90     l=0.0; r=1000.0;
 91     while(r-l>1e-4)
 92     {
 93         mid=(l+r)/2.0;
 94         if(spfa()) l=mid;
 95         else r=mid;
 96     }
 97     printf("%.2lf\n",mid);
 98 }
 99 
100 int main()
101 {
102     while(scanf("%d%d",&n,&m)!=EOF) read(),go();
103     return 0;
104 }

 

 

posted @ 2013-01-09 22:07  proverbs  阅读(669)  评论(0编辑  收藏  举报