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 }
没有人能阻止我前进的步伐,除了我自己!