本文主要是介绍AcWing 348. 沙漠之王(0/1分数规划),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
0/1分数规划
从该题可以归纳出的0/1分数规划的一般模型:给定正整数 a 1 , a 2 . . . a n a_{1},a_{2}...a_{n} a1,a2...an以及 b 1 , b 2 . . . b n b_{1}, b_{2}...b_{n} b1,b2...bn从中选出若干对的a和b的和的商,求商的最大值Max或者最小值Min,即:
∑ a [ i ] ∑ b [ i ] ∈ [ M i n , M a x ] \frac{\sum_{}a[i]}{\sum_{}b[i]}∈[Min, \ Max] ∑b[i]∑a[i]∈[Min, Max]
由于不知道他们的商是多少,我们不妨先假设 ∑ a [ i ] ∑ b [ i ] = m \frac{\sum_{}a[i]}{\sum_{}b[i]}=m ∑b[i]∑a[i]=m
find_Min
1.若 任意 ∑ ( a [ i ] − m ∗ b [ i ] ) ≥ 0 \sum (a[i] - m * b[i]) ≥ 0 ∑(a[i]−m∗b[i])≥0 ⇔ ∑ ( a [ i ] − m ∗ b [ i ] ) m i n ≥ 0 \sum (a[i] - m * b[i])_{min}≥ 0 ∑(a[i]−m∗b[i])min≥0 ⇔ ( ∑ a [ i ] ∑ b [ i ] ) m i n ≥ m (\frac{\sum a[i]}{\sum b[i]})_{min} ≥ m (∑b[i]∑a[i])min≥m
即 M i n ≥ m Min ≥ m Min≥m
2.若 存在 ∑ ( a [ i ] − m ∗ b [ i ] ) < 0 \sum (a[i] - m * b[i]) < 0 ∑(a[i]−m∗b[i])<0 ⇔ ∑ ( a [ i ] − m ∗ b [ i ] ) m i n < 0 \sum (a[i] - m * b[i])_{min}< 0 ∑(a[i]−m∗b[i])min<0 ⇔ ( ∑ a [ i ] ∑ b [ i ] ) m i n < m (\frac{\sum a[i]}{\sum b[i]})_{min} < m (∑b[i]∑a[i])min<m
即 M i n < m Min < m Min<m
find_Max
1.若 存在 ∑ ( a [ i ] − m ∗ b [ i ] ) ≥ 0 \sum (a[i] - m * b[i]) ≥ 0 ∑(a[i]−m∗b[i])≥0 ⇔ ∑ ( a [ i ] − m ∗ b [ i ] ) m a x ≥ 0 \sum (a[i] - m * b[i])_{max}≥ 0 ∑(a[i]−m∗b[i])max≥0 ⇔ ( ∑ a [ i ] ∑ b [ i ] ) m a x ≥ m (\frac{\sum a[i]}{\sum b[i]})_{max} ≥ m (∑b[i]∑a[i])max≥m
即 M a x ≥ m Max ≥ m Max≥m
2.若 任意 ∑ ( a [ i ] − m ∗ b [ i ] ) < 0 \sum (a[i] - m * b[i]) < 0 ∑(a[i]−m∗b[i])<0 ⇔ ∑ ( a [ i ] − m ∗ b [ i ] ) m a x < 0 \sum (a[i] - m * b[i])_{max}< 0 ∑(a[i]−m∗b[i])max<0 ⇔ ( ∑ a [ i ] ∑ b [ i ] ) m a x < m (\frac{\sum a[i]}{\sum b[i]})_{max} < m (∑b[i]∑a[i])max<m
即 M a x < m Max < m Max<m
二分
综上所诉,我们可以二分查找m
1.当 ∑ a [ i ] ∑ b [ i ] ≥ m \frac{\sum a[i]}{\sum b[i]} ≥ m ∑b[i]∑a[i]≥m,即m ≤ {Max or Min},→ l = mid;
2.当 ∑ a [ i ] ∑ b [ i ] < m \frac{\sum a[i]}{\sum b[i]} < m ∑b[i]∑a[i]<m,即m > {Max or Min},→ r = mid;
348. 沙漠之王
思路:
成本为c, 长度为v
1.题意求生成树的 ∑ c [ i ] ∑ v [ i ] \frac{\sum c[i]}{\sum v[i]} ∑v[i]∑c[i]的Min, 不妨设 ∑ c [ i ] ∑ v [ i ] = m \frac{\sum c[i]}{\sum v[i]} = m ∑v[i]∑c[i]=m
2.若 任意 ∑ ( c [ i ] − m ∗ v [ i ] ) ≥ 0 \sum (c[i] - m * v[i]) ≥ 0 ∑(c[i]−m∗v[i])≥0
⇔ 以 ( c [ i ] − m ∗ v [ i ] ) (c[i] - m * v[i]) (c[i]−m∗v[i])为边权的最小生成树
⇔ ∑ ( c [ i ] − m ∗ v [ i ] ) m i n ≥ 0 \sum (c[i] - m * v[i])_{min}≥ 0 ∑(c[i]−m∗v[i])min≥0
⇔ ( ∑ c [ i ] ∑ v [ i ] ) m i n ≥ m (\frac{\sum c[i]}{\sum v[i]})_{min} ≥ m (∑v[i]∑c[i])min≥m
即 m 小于等于Min
则 l = mid 反正则 r = mid
3. 稠密图用prim算法 O ( n 2 ) O(n^2) O(n2), 用Kruskal O ( m l o g m ) O(mlogm) O(mlogm) , m = n 2 m = n ^ 2 m=n2 会超时
样例输入:
4
0 0 0
0 1 1
1 1 2
1 0 3
0
样例输出:
1.000
代码:
//最优比例生成树
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int N = 1005, M = 1e6 + 10, INF = 10000005;
typedef pair<int, int> PII;
int n;
double mm;double c[N][N], v[N][N], dist[N];
bool st[N];struct Point{int x, y, d;
}point[N];double dis(Point a, Point b)
{return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}double prim(double m)
{for(int i = 1; i <= n; i ++ ) dist[i] = INF;memset(st, false, sizeof st);double sum = 0;for(int i = 0; i < n; i ++ ){int t = -1;for(int j = 1; j <= n; j ++ )if(!st[j] && (t == -1 || dist[j] < dist[t]))t = j;if(i) sum += dist[t];for(int j = 1; j <= n; j ++ ){double tmp = c[t][j] - v[t][j] * m;if(!st[j]) dist[j] = min(dist[j], tmp);}st[t] = true;}return sum;
}int main()
{while(cin >> n){if(n == 0) break;for(int i = 1; i <= n; i ++ ){int x, y, d;cin >> x >> y >> d;point[i] = {x, y, d};}for(int i = 1; i <= n; i ++ )for(int j = i + 1; j <= n; j ++ ){c[i][j] = c[j][i] = (double)abs(point[i].d - point[j].d);v[i][j] = v[j][i] = dis(point[i], point[j]);}double l = 0, r = 100;while(r - l >= 1e-4){double mid = (l + r) / 2.0;if(prim(mid) >= 0) l = mid;else r = mid;}printf("%.3lf\n", r); }return 0;
}
这篇关于AcWing 348. 沙漠之王(0/1分数规划)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!