POJ 3621 Sightseeing Cows 01分数规划(参数搜索)+最短路
2013-06-26 10:10
489 查看
题目大意:在一个有向图中,点有点权,边有边权,找一个环使环上的点权之和与边权之和的比最大。 ( 学名: 最优比率生成环..? )
解题思路: 首先必备的知识点是分数规划,还得去看Amber的《最小割模型在信心学竞赛中的应用》....(貌似近期每篇都要提一提...)
可以跳过前面的直接从第十页开始看, 了解分数规划特别是01分数规划。
总的来说,就是求一个环,使得环上经过的点的点权Vi,经过的边的边权,Ej, sum( Vi )/sum( Ej ) 最大。
为了简单表示,我们把任意一个环的sum( Vi )表示为V, sum( Ej ) 表示为E。
就是求一个m=max( V /E )
V - E*m = 0
我们令h(m)=V - E*m
h(m) 是一个非递增的函数 (这个自己画画就知道了)
二分枚举m,
当h(m)=0时的m就是我们要求的值。(至于为什么,看论文...分数规划)
上面是一个大体的思路,
但是对于每次枚举的m,
我们不可能枚举每种状态下的V 和 E , 然后求出确切的 V-E*m的值,情况太多,也不现实,
所以我们退而求其次,对于每个m,我们求h(m)是否大于0即可,
在一定的精度条件下,恰好使h(m)>0 和h(m)<0的那个分界点就可以认定为我们要求的值。
然后就是判断h(m)>0的方法了:(这个可以在图上画画转化为自己的思路)
每枚举一个m时重构图,
对于原图的每条边c(u,v)=Ei, 建c(u,v)=Ei*m ,点权不变,
然后每个环上的权值为点权减去边权,
如果出现正环了就说明h(m) > 0 , (从图形上理解就是m尚未达到上限,还有继续往上调的空间)
就这样,判断在一定精度下h(m)恰好大于0的m的值即可。
具体实现看代码:
解题思路: 首先必备的知识点是分数规划,还得去看Amber的《最小割模型在信心学竞赛中的应用》....(貌似近期每篇都要提一提...)
可以跳过前面的直接从第十页开始看, 了解分数规划特别是01分数规划。
总的来说,就是求一个环,使得环上经过的点的点权Vi,经过的边的边权,Ej, sum( Vi )/sum( Ej ) 最大。
为了简单表示,我们把任意一个环的sum( Vi )表示为V, sum( Ej ) 表示为E。
就是求一个m=max( V /E )
V - E*m = 0
我们令h(m)=V - E*m
h(m) 是一个非递增的函数 (这个自己画画就知道了)
二分枚举m,
当h(m)=0时的m就是我们要求的值。(至于为什么,看论文...分数规划)
上面是一个大体的思路,
但是对于每次枚举的m,
我们不可能枚举每种状态下的V 和 E , 然后求出确切的 V-E*m的值,情况太多,也不现实,
所以我们退而求其次,对于每个m,我们求h(m)是否大于0即可,
在一定的精度条件下,恰好使h(m)>0 和h(m)<0的那个分界点就可以认定为我们要求的值。
然后就是判断h(m)>0的方法了:(这个可以在图上画画转化为自己的思路)
每枚举一个m时重构图,
对于原图的每条边c(u,v)=Ei, 建c(u,v)=Ei*m ,点权不变,
然后每个环上的权值为点权减去边权,
如果出现正环了就说明h(m) > 0 , (从图形上理解就是m尚未达到上限,还有继续往上调的空间)
就这样,判断在一定精度下h(m)恰好大于0的m的值即可。
具体实现看代码:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <queue> using namespace std; #define N 1010 #define M 5010 #define INF 1e6 #define FOR(i,l,r) for(int i=(l);i<=(r);++i) #define REP(i,n) for(int i=0;i<=(n);++i) struct { int to,next; int c; } edge[M]; double dis ; int v ; int out ; bool visit ,flag ; int n,m; int head ,ip; void add(int u,int v,int c) { edge[ip].to=v; edge[ip].c=c; edge[ip].next=head[u]; head[u]=ip++; } bool solve(double x) { memset(flag,0,sizeof(flag)); memset(visit,0,sizeof(visit)); memset(dis,0,sizeof(dis)); memset(out,0,sizeof(out)); queue<int>q; FOR(start,1,n)//枚举每个没被访问过的点为起点开始寻找环 { if(flag[start]) continue; //从这往后基本上就是spfa判正环的思路,用其他的会TLE dis[start]=0; q.push(start); visit[start]=1; int top,to; double temp; while(!q.empty()) { top=q.front(); q.pop(); visit[top]=0; flag[top]=1; for(int p=head[top]; p!=-1; p=edge[p].next) { to=edge[p].to; temp=edge[p].c*x - v[to];//我每次枚举mid没有重构图,直接把边权*mid了,效果是一样的 if(dis[to]<dis[top] - temp ) { dis[to]=dis[top] - temp; if(!visit[to]) { if(++out[to]>=n) return 1; //有正环,h(mid)>0 q.push(to); visit[to]=1; } } } } } return 0;//无正环,h(mid)<=0 } int main() { int x,y,c; while(cin>>n>>m) { memset(head,-1,sizeof(head)); ip=0; FOR(i,1,n) scanf("%d",&v[i]); while(m--) { scanf("%d%d%d",&x,&y,&c); add(x,y,c); } double exp=0.001;//调节精度 double r=1000,l=0,mid; while(r-l>exp)//二分枚举每个mid,判断在枚举mid时是否出现正环 { if(solve(mid)) l=mid; else r=mid; mid=(l+r)/2.0; } if(l>exp) printf("%.2f\n",l);//建议不要输出mid,输出l,因为精度原因mid可能与正确答案有误差,但l是一定满足的 else printf("0"); } return 0; }
相关文章推荐
- POJ-3621 Sightseeing Cows 01分数(参数搜索)规划问题-最优比率环
- poj-3621-Sightseeing Cows-01分数规划+spfa判负环
- POJ 3621 Sightseeing Cows (bellman-Ford + 01分数规划)
- poj 3621 Sightseeing Cows (最优比率生成环 01分数规划问题 )
- POJ 3621 Sightseeing Cows 最大密度环 01分数规划
- poj 3621 Sightseeing Cows 01分数规划
- POJ 3621 Sightseeing Cows 01分数规划
- POJ 3621 Sightseeing Cows | 01分数规划
- POJ 3621 Sightseeing Cows(01分数规划)
- poj 3621 Sightseeing Cows(最优比例生成环,01分数规划)
- POJ 3621 Sightseeing Cows 01分数规划,最优比例环的问题
- POJ-3621 Sightseeing Cows 最优比率环、01分数规划
- POJ 3621 Sightseeing Cows(01分数规划+二分+spfa判负环)
- 01分数规划 ——最有比率环 pku 3621 Sightseeing Cows
- POJ 3621(0/1分数规划,二分) Sightseeing Cows
- pku 3621 01分数规划 sightseeing cows 解题报告
- poj 3621 Sightseeing Cows ( 求最优比例生成环/01分数规划 )
- poj 3621 Sightseeing Cows 负环探测解参数搜索
- POJ 3621 Sightseeing Cows(最优比率环/01分数规划)
- poj 3621 Sightseeing Cows 【最优比例环】 【0-1分数规划 + SPFA判负环】