学习笔记6:01分数规划

F - Beautiful Path (atcoder.jp)

分析:给了我们一个图,图中每条边有一个美观度和成本,要求我们找到从点1到点n的最大贡献(贡献为sum路径上美观度/sum路径上成本和)

01分数规划很好解决这个问题(求最优比率)

答案的公式为

ans=max({\tfrac{\sum bi}{ \sum ci}})

(以下公式中省略了max)

转化一下变成

ans*\sum ci-\sum bi=0

如何求解这样的式子?

二分答案,把边替换成ans*ci- bi,求出1-n的最短路(为什么是求最短路?下文揭晓),此时

dist[n]=ans*\sum ci-\sum bi

为什么是最短路呢?而不是最长路?

因为dist[n]如果小于等于0,就说

ans*\sum ci-\sum bi<=0

,此时ans一定存在一个更大的解 使得

ans*\sum ci-\sum bi=0

而我们就是希望求得一个最大的ans,所以我们求n的最短路使得式子的值尽可能小

dist[n]<=0说明ans的最大解一定大于等于当前的尝试的比率,反而则一定小于等于(由于是小数二分记得限定二分次数)

二分的判断条件 check()具体实现:由于所有的边都是从小的点连向大的点,并且一定存在一条1-n的路径,符合拓扑序

我们可以尝试把边替换成ans*ci- bi,然后通过dp求出1-n的最短路。

#include <bits/stdc++.h>

using namespace std;

const int N = 1000010,M=2*N;
int h[N], e[M], w1[M],w2[M], ne[M], idx;
double q[N], dist[N];
bool st[N];
void add(int a, int b, int t1 ,int t2) 
{
    e[idx] = b, w1[idx] = t1,w2[idx] = t2, ne[idx] = h[a], h[a] = idx ++ ;
}

	int n, m;
bool check(double mid){
    for(int i=1;i<=n;i++) dist[i]=1e18;
    dist[1]=0;
    for(int i=1;i<=n;i++){
        for(int j=h[i];~j;j=ne[j]){
            int k=e[j];
            dist[k]=min(dist[k],dist[i]+mid*w2[j]-w1[j]);
        }
    }
    return dist[n]<=0;
}
signed main() {
	cin >> n >> m;
    memset(h,-1,sizeof h);

	for (int i = 0; i < m; i++) {
		int u, v, b, c;
		std::cin >> u >> v >> b >> c;

		add(u,v,b,c);
	}

	double l = 0, r = 1e9;
	for (int t = 0; t <= 100; t++) {
		double mid = (l + r) / 2;

		if (check(mid)) {
			l = mid;
		} else {
			r = mid;
		}
	}
	printf("%.12lf",l);

}

  • 11
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值