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 }

 

 

你可能感兴趣的:(poj)