每日一记:分数规划
来源:互联网 发布:数据库中省略为什么 编辑:程序博客网 时间:2024/06/07 01:34
以下部分内容引用论文内容。
分数规划一般形式:
解向量x在解空间S内, a(x)与 b(x)都是连续的实值函数。
求解过程:
1、令g(λ) = min{a(x) -λ*b(x)} (x∈S),g(λ)是一个严格递减的函数
证明:设 λ1 < λ2, x1最小化了g(λ)。则
g(λ1) = min {a(x) - t1*b(x)}
= a(x1) - λ1*b(x1)
> a(x1) - λ2*b(x1) //b(x) > 0
>= min {a(x) - λ2*b(x)} = g(λ2)
Dinkelbach定理:若λ*为原规划的最优解,则g(λ)=0当且仅当λ=λ*。
即只需求出λ*使得g(λ*)=0即可。
2、设λ*为该规划的最优解。
使用二分法可求解。
Example:
Description
Bryan成为了一名土木工程师,负责一个国家的道路建设!这个国家有N个城市,从1到N标号。M条可以修建的路,每条路连接两个城市,并且有修建需要的花费。现在Bryan需要从M条路中选择一些修建,使得国家中任意两个城市都能连通。当然可行方案有很多,Bryan想选择平均修一条路的花费最小的那种方案。如果没有能连通所有城市的方案,输出-1。
Input
第1行: 2个正整数,N M (1<=N<=1000, 0<=M<=100000),N表示城市的数量,M表示可以修建的路的数量。
第2行到第M+1行:每行三个整数,u v c (1<=u,v<=N 0<=c<=1000),表示城市u和城市v之间可以花费费用c修建一条道路。
Output
输出最小的平均花费,四舍五入保留两位小数。如果不存在可行方案,输出-1。
-------------------------------------------------------------------------------------------------------------------
解法:本题可贪心也可分数规划,这里用分数规划求解。
1、设sum为所选总花费,cnt为所选道路数,题目所求为使得sum/cnt最小,满足分数规划的条件、。
2、构造函数g(λ) = min{sum -λ*cnt}。
二分λ:对于λ*,为了求出g(λ*),我们把每条边的边权变为w - λ, 按照此边权求最小生成树即可,注意要把所有负边权也加入最小生成树中,这样总和一定是最小的sum -λ*cnt。
#include <iostream>#include <algorithm>#include <vector>#include <cstdio>using namespace std;#define MP(x,y)make_pair(x, y)const double eps = 1e-3;int pre[1005], n, m;void init (){for (int i = 0; i < 1005; i ++){pre[i] = i;}}int find (int x){return pre[x] == x ? x : pre[x] = find (pre[x]);}void Union (int x, int y){pre[find (x)] = find (y);}double cal (const vector<pair<int, pair<int, int> > >& g, double t){init ();double ans = 0;int num = 0;for (int i = 0; i < g.size (); i ++){int u = g[i].second.first;int v = g[i].second.second;int w = g[i].first;if (find (u) != find (v)){Union (u, v);ans += (double)w-t;num ++;}else if (w - t < 0){ans += (w-t);}}if (num < n-1)return -1;return ans;}int main (){freopen ("6.in", "r", stdin);cin >> n >> m;vector<pair<int, pair<int, int> > > edge;for (int i = 1; i <= m; i ++){int u, v, c;cin >> u >> v >> c;edge.push_back (MP (c, MP (u, v)));}sort (edge.begin (), edge.end ());if (cal (edge, 0) == -1){puts ("-1");return 0;}double high = 100000.0, low = 0.0, mid;while (low + eps < high){mid = (low + high)/2.0;if (cal (edge, mid) - eps> 0)low = mid;elsehigh = mid;}printf ("%.2f\n", low);}
- 每日一记:分数规划
- acm每日一练之分数加减法
- 分数规划
- 分数规划
- 分数规划
- 分数规划
- 分数规划
- 每日一记
- 每日一记
- 每日一记。encodeURIComponent()
- 每日一记
- 每日一记----------dynamic_cast
- 每日一记
- 每日一记
- 每日一记
- 每日一记
- java每日一记
- Android每日一记
- 【IOS网络通信】Mac&IOS Socket编程
- 使用shell脚本自动更新动态域名
- 使用 DBMS_PARALLEL_EXECUTE 更新大表
- 二叉树——建数字树,知先序、中序,输出后序
- java实现上传图片进行切割
- 每日一记:分数规划
- mysql显示SQL语句执行所消耗的时间
- 携程移动网站优化实践
- 组合模式理解Cocosd-x游戏引擎之addChild函数
- 简单usb驱动代码记录
- linux(Centos)上memcacheq成功安装及使用
- 最后我就拿着加多宝喝着走了…
- Unity IOC注入详细配置(MVC,WebApi)
- Android高性能编程注意事项