http://lghjx.573114.com/Blog/Html/103D/275536.html
下面的不是很清楚 ,这个 比较好。
简介:
详情 前参见 国家集训队论文 2007年 胡伯涛 论文
题意:求存在一个环路,所有的点权之和/所以的边权之和 最大是多少?
http://poj.org/problem?id=3621
算法:此题是对01分数规划的应用,那么首先明白01分数规划的思想.
01分数规划的思想的描述如下:令c=(c1,c2,…,cn)和d=(d1,d2,…,dn)为n维整数向量,那么一个0-1分数规划问题用公式描述如下:FP: 最小化(c1x1+…cnxn)/(d1x1…dnxn)=cx/dx xi∈{0,1}这里x表示列向量(x1,x2,…,xn)T .0-1值向量的子集Ω称作可行域,而x则是Ω的一个元素,我们称x为可行解。即可以简化为y=c/d.那么再演变一下:y-c/d=0.我们目标是求y.那么我们可以假设函数f(y)=y-c/d.
重要结论:
对于分数规划问题,有许多算法都能利用下面的线性目标函数解决问题。
Q(L): 最小化 cx-Ldx xi∈{0,1}
记z(L)为Q(L)的最值。令x*为分数规划的最优解,并且令L*=(cx*)/(dx*)(注:分数规划的最值)。那么下面就容易知道了:
z(L) > 0 当且仅当 L<L*
z(L) = 0 当且仅当 L=L*
z(L) < 0 当且仅当 L>L*
此外,Q(L*)的最优解也能使分数规划最优化。因此,解决分数规划问题在本质上等同于寻找L=L*使z(L)=0
因此,求解f(y)=0,为其函数的最优解,即可以利用二分的思想逐步推演y,从而求得最优解.
回到题目,我们知道是求解segma(f[V])/segma(E[v])的最大值,同时每个结点对应一个点权,每条边对应一个边权,那么我们就可以联想到应用01分数规划的思想来求解.而01分数规划是与二分紧紧联系在一起的.那么怎么应用二分求解呢?
我们首先想想当仅仅有2个结点环路的时候,问题就演变为f(y)=y-c/d,而y是通过二分逐步推算出来的,那么我们的任务就变为在一定的精度范围内测试求解其最优解.当y-c/d>0时,y减少; y-c/d<0时,y增大.在2个结点之间,那么我们就可用重新将图的权变为y-c/d,这样问题就回到2个结点的环路是否存在负权回路,存在说明y-c/d<0,不存在y-c/d>0.从而进一步推算最优解y。
/*
01整数规划问题 ,
01整数规划问题 分为两类 最大化 ,最小化
以最小化 如 求 最小值 l=ax/bx ,(ax bx是一些数的和),变形为 ax-l*bx=0,我们令 f(x)=min(ax-l*bx),我们要求的是这样的一个 l 对于 给定的 l
首先 ax1-l*bx1=0
不存在 x 使得 (因为 l 是我们求的 最小值)
ax-l*bx > 0
这样的话 ax>l*bx ;
关键是我们如何求这个l 呢? 有上面的 我们可以得到,用 二分法,求 l ,
对于 f(x)=min(ax-l*bx)
对于给定的 l
若 f(x)<0 则说明 l 偏大
若 f(x)>0 说明 l 偏小
对于 图上的 01 整数规划 我门只需要将 边权变为 ax-l*bx 或者 l*bx- ax;
例如 对于 最优比率树 : 大意:给定一张图,每条边有一个收益值和一个花费值,求一个生成树,要求花费/收益最小,输出这个值
我们只需要将 边权 变为 a1-l*b1 然后 求最小生成树 就行 判断 求和的 ai-l*bi 的值 于0 的大小
*/
poj 2976 Dropping tests 【最优比例点】
http://poj.org/problem?id=2976
1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<cmath> 5 #include<queue> 6 #include<set> 7 #include<map> 8 #define Min(a,b) a>b?b:a 9 #define Max(a,b) a>b?a:b 10 #define CL(a,num) memset(a,num,sizeof(a)); 11 #define inf 9999999 12 #define maxn 1030 13 #define eps 1e-6 14 15 using namespace std; 16 int cmp(const double a,const double b) 17 { 18 return a>b; 19 } 20 double a[maxn],b[maxn]; 21 double d[maxn]; 22 int main() 23 { 24 __int64 n,k,i; 25 while(scanf("%I64d%I64d",&n,&k),n+k) 26 { 27 for(i=1;i<=n;i++) 28 { 29 scanf("%lf",&a[i]); 30 } 31 for(i=1;i<=n;i++)scanf("%lf",&b[i]); 32 double l=0,r=-1; 33 for(i=1;i<=n;i++) 34 { 35 if(a[i]/(b[i]*1.0)>r)r = a[i]/(b[i]*1.0); 36 } 37 38 int m=n-k; 39 double ans,mid; 40 r=100.0; 41 while(r-l>eps) 42 { 43 mid=(l+r)/2; 44 for(i=1;i<=n;i++)d[i]=a[i]*100.0-mid*b[i]; 45 sort(d+1,d+n+1,cmp); 46 47 48 49 50 double temp=0; 51 for(i=1;i<=m;i++)temp+=d[i]; 52 if(temp>=0) 53 { 54 55 56 57 58 l=mid; 59 60 } 61 else r=mid; 62 } 63 64 65 printf("%.0lf\n",mid); 66 67 } 68 }
【例题2Poj2728Desert King——最优比率生成树】
http://poj.org/problem?id=2728
1 #include<stdio.h> 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 #include<queue> 7 #include<set> 8 #include<map> 9 #define Min(a,b) a>b?b:a 10 #define Max(a,b) a>b?a:b 11 #define CL(a,num) memset(a,num,sizeof(a)); 12 #define inf 9999999 13 #define maxn 1030 14 #define eps 1e-6 15 16 using namespace std; 17 struct node 18 { 19 double x,y,h; 20 }p[maxn]; 21 struct cnode 22 { 23 int k; 24 double w; 25 cnode(int kk,double ww): k(kk),w(ww){} 26 friend bool operator < (cnode a,cnode b) 27 { 28 return a.w>b.w; 29 } 30 }; 31 int n; 32 double mat[maxn][maxn],cost[maxn][maxn],dis[maxn],vis[maxn]; 33 priority_queue<cnode>que; 34 void init() 35 { 36 int i,j; 37 for(i=0;i<=n;i++) 38 { 39 for(j=0;j<=n;j++) 40 { 41 mat[i][j]=inf; 42 cost[i][j]=0; 43 } 44 } 45 } 46 47 double prim(double mid) 48 { 49 int i,j,k; 50 double res=0; 51 for(i=0;i<=n;i++) 52 { 53 dis[i]=inf; 54 vis[i]=0; 55 } 56 dis[0]=0; 57 58 for(i=0;i<n;i++) 59 { 60 double min=inf; 61 for(j=0;j<n;j++) 62 { 63 if(!vis[j]&&dis[j]<min) 64 { 65 min=dis[j]; 66 k=j; 67 } 68 } 69 vis[k]=1; 70 res+=dis[k]; 71 for(j=0;j<n;j++) 72 { 73 double t=cost[k][j]-mid*mat[k][j]; 74 if(!vis[j]&&mat[k][j]!=inf&&dis[j]>t) 75 { 76 dis[j]=t; 77 } 78 } 79 80 } 81 return res; 82 } 83 int main() 84 { 85 int i,j; 86 while(scanf("%d",&n),n) 87 { 88 for(i=0;i<n;i++) 89 { 90 scanf("%lf%lf%lf",&p[i].x,&p[i].y,&p[i].h); 91 } 92 init(); 93 94 double max=-1; 95 for(i=0;i<n;i++) 96 for(j=0;j<n;j++) 97 { 98 double l=sqrt((p[i].x-p[j].x)*(p[i].x-p[j].x)+(p[i].y-p[j].y)*(p[i].y-p[j].y)); 99 double w=fabs(p[i].h-p[j].h); 100 mat[i][j]=l; 101 mat[j][i]=l; 102 if(w>max)max=w; 103 cost[i][j]=w; 104 cost[j][i]=w; 105 106 } 107 108 double l=0,r=max,mid; 109 while(r-l>eps) 110 { 111 mid=(l+r)/2; 112 if(prim(mid) >= 0) 113 { 114 115 l = mid; 116 } 117 else r = mid; 118 119 } 120 printf("%.3lf\n",mid); 121 } 122 123 }
【例题3Poj3621Sightseeing Cows——最优比率环】
spfa (判负环)
http://poj.org/problem?id=3621
1 #include<stdio.h> 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 #include<queue> 7 #include<set> 8 #include<map> 9 #define Min(a,b) a>b?b:a 10 #define Max(a,b) a>b?a:b 11 #define CL(a,num) memset(a,num,sizeof(a)); 12 #define inf 9999999 13 #define maxn 1030 14 #define eps 1e-6 15 using namespace std; 16 struct node 17 { 18 int u; 19 int w; 20 node (int uu,int ww):u(uu),w(ww){} 21 }; 22 vector<node>p[maxn]; 23 int n,m; 24 queue<int>que; 25 double dis[maxn]; 26 int vis[maxn],tol[maxn],a[maxn]; 27 bool spfa(double mid) 28 { 29 int i; 30 while(!que.empty())que.pop(); 31 32 33 for(i=1;i<=n;i++)que.push(i); 34 35 for(i=1;i<=n;i++) 36 dis[i]=inf; 37 38 CL(vis,true); CL(tol,0); 39 40 while(!que.empty()) 41 { 42 int u=que.front();que.pop(); 43 vis[u]=0; 44 for(i=0;i<p[u].size();i++) 45 { 46 node b=p[u][i]; 47 int v=b.u; 48 double t = -a[v] + mid*b.w; 49 if(dis[v]>t+dis[u]) 50 { 51 tol[v]++; 52 dis[v]=t+dis[u]; 53 if(tol[v]>=n)return true; 54 if(!vis[v]) 55 { 56 vis[v]=1; 57 que.push(v); 58 } 59 60 } 61 62 } 63 } 64 return false ; 65 } 66 int main() 67 { 68 int i,x,y,z; 69 while(scanf("%d%d",&n,&m)!=EOF) 70 { 71 for(i=1;i<=n;i++)scanf("%d",&a[i]); 72 for(i=0;i<=n;i++)p[i].clear(); 73 74 75 while(m--) 76 { 77 scanf("%d%d%d",&x,&y,&z); 78 p[x].push_back(node(y,z)); 79 80 } 81 double l=0,r=2500,mid,ans=-1; 82 while(r-l>eps) 83 { 84 mid = (l+r)/2; 85 if(spfa(mid)) 86 { 87 ans=mid; 88 l=mid; 89 } 90 else r=mid; 91 } 92 if(ans<-1)puts("0"); 93 else printf("%.2lf\n",ans); 94 95 } 96 }