标签:inter people engine ESS dig targe proc 0-1分数规划 lin
Time Limit: 3000MS | Memory Limit: 65536K | |
Total Submissions:33847 | Accepted: 9208 |
Description
Input
Output
Sample Input
4 0 0 0 0 1 1 1 1 2 1 0 3 0
Sample Output
1.000
有带权图G, 对于图中每条边e[i], 都有benifit[i](收入)和cost[i](花费), 我们要求的是一棵生成树T, 它使得 ∑(benifit[i]) / ∑(cost[i]), i∈T 最大(或最小).
这显然是一个具有现实意义的问题.
设x[i]等于1或0, 表示边e[i]是否属于生成树.
则我们所求的比率 r = ∑(benifit[i] * x[i]) / ∑(cost[i] * x[i]), 0≤i<m .
为了使 r 最大, 设计一个子问题---> 让 z = ∑(benifit[i] * x[i]) - l * ∑(cost[i] * x[i]) = ∑(d[i] * x[i]) 最大 (d[i] = benifit[i] - l * cost[i]) , 并记为z(l). 我们可以兴高采烈地把z(l)看做以d为边权的最大生成树的总权值.
然后明确两个性质:
1. z单调递减
证明: 因为cost为正数, 所以z随l的减小而增大.
2. z( max(r) ) = 0
证明: 若z( max(r) ) < 0, ∑(benifit[i] * x[i]) - max(r) * ∑(cost[i] * x[i]) < 0, 可化为 max(r) < max(r). 矛盾;
若z( max(r) ) >= 0, 根据性质1, 当z = 0 时r最大.
到了这个地步, 七窍全已打通, 喜欢二分的上二分, 喜欢Dinkelbach的就Dinkelbach.
时间 O( O(MST) * log max(r) )
空间 O( O(MST) )
C++代码
二分法
/* *@Author: Agnel-Cynthia *@Language: C++ */ //#include <bits/stdc++.h> #include<iostream> #include<algorithm> #include<cstdlib> #include<cstring> #include<cstdio> #include<string> #include<vector> #include<bitset> #include<queue> #include<deque> #include<stack> #include<cmath> #include<list> #include<map> #include<set> //#define DEBUG #define RI register int #define endl "\n" using namespace std; typedef long long ll; //typedef __int128 lll; const int N=1000+10; const int M=100000+10; const int MOD=1e9+7; const double PI = acos(-1.0); const double EXP = 1E-8; const int INF = 0x3f3f3f3f; //int t,n,m,k,p,l,r,u,v; const int maxn = 1005; //ll a[maxn],b[maxn]; struct node { int x , y ,z ; }edge[maxn]; int n ; double mp[maxn][maxn]; double dis(double x1 ,double y1,double x2,double y2){ return sqrt(1.0*(x1-x2) * (x1 - x2) + 1.0 * (y1 - y2) * (y1 - y2)); } void creat(){ for(int i = 1;i <= n ;i ++){ for(int j = 1;j <= n ; j++){ mp[i][j] = dis(edge[i].x,edge[i].y,edge[j].x,edge[j].y); } } } double d[maxn]; bool vis[maxn]; double prime(double mid){ memset(vis,0,sizeof vis); for(int i = 1;i <= n ; i++){ d[i] = abs(edge[1].z - edge[i].z) - mp[1][i] * mid; } vis[1] = true; double ans = 0; for(int i = 1;i < n ; i++){ int v = -1;double MIN = INF; for(int j = 1;j <= n ; j++){ if(MIN >= d[j] && !vis[j]){ v = j; MIN = d[j]; } } if(v == -1) break; vis[v] = true; ans += MIN; for(int j = 1;j <= n ; j++){ if(!vis[j] && (fabs(edge[v].z - edge[j].z) - mp[v][j] * mid) < d[j]) d[j] = (fabs(edge[v].z - edge[j].z) - mp[v][j] * mid); } } return ans ; } int main() { #ifdef DEBUG freopen("input.in", "r", stdin); //freopen("output.out", "w", stdout); #endif // ios::sync_with_stdio(false); // cin.tie(0); // cout.tie(0); while(cin >> n && n){ for(int i = 1;i <= n ; i++){ cin >> edge[i].x >> edge[i].y >> edge[i].z; } double l = 0, r = 40.0; double mid = 0; creat(); while(fabs(r - l) > EXP){ mid = (l + r) / 2; if(prime(mid) >= 0) l = mid; else r = mid; } printf("%.3lf\n",mid ); } #ifdef DEBUG printf("Time cost : %lf s\n",(double)clock()/CLOCKS_PER_SEC); #endif //cout << "Hello world!" << endl; return 0; }
Dinkelbach
/* *@Author: Agnel-Cynthia *@Language: C++ */ //#include <bits/stdc++.h> #include<iostream> #include<algorithm> #include<cstdlib> #include<cstring> #include<cstdio> #include<string> #include<vector> #include<bitset> #include<queue> #include<deque> #include<stack> #include<cmath> #include<list> #include<map> #include<set> //#define DEBUG #define RI register int #define endl "\n" using namespace std; typedef long long ll; //typedef __int128 lll; const int N=1000+10; const int M=100000+10; const int MOD=1e9+7; const double PI = acos(-1.0); const double EXP = 1E-8; const int INF = 0x3f3f3f3f; //int t,n,m,k,p,l,r,u,v; //ll a[maxn],b[maxn]; #define Rep(i,l,r) for(i=(l);i<=(r);i++) #define rep(i,l,r) for(i=(l);i< (r);i++) #define Rev(i,r,l) for(i=(r);i>=(l);i--) #define rev(i,r,l) for(i=(r);i> (l);i--) #define Each(i,v) for(i=v.begin();i!=v.end();i++) #define r(x) read(x) int CH , NEG ; template <typename TP>inline void read(TP& ret) { ret = NEG = 0 ; while (CH=getchar() , CH<‘!‘) ; if (CH == ‘-‘) NEG = true , CH = getchar() ; while (ret = ret*10+CH-‘0‘ , CH=getchar() , CH>‘!‘) ; if (NEG) ret = -ret ; } #define maxn 1010LL #define infi 100000000LL #define eps 1E-8F #define sqr(x) ((x)*(x)) template <typename TP>inline bool MA(TP&a,const TP&b) { return a < b ? a = b, true : false; } template <typename TP>inline bool MI(TP&a,const TP&b) { return a > b ? a = b, true : false; } int n; int x[maxn], y[maxn], h[maxn]; double v[maxn][maxn], c[maxn][maxn]; bool vis[maxn]; double w[maxn]; double rv[maxn];/// inline double prim(double M) { int i, j, k; double minf, minw; double sumc = 0, sumv = 0;/// memset(vis,0,sizeof vis); Rep (i,2,n) w[i] = v[1][i]-M*c[1][i], rv[i] = v[1][i];/// vis[1] = true, minf = 0; rep (i,1,n) { minw = infi; Rep (j,1,n) if (!vis[j] && w[j]<minw) minw = w[j], k = j; sumv += rv[k], sumc += rv[k]-w[k];/// minf += minw, vis[k] = true; Rep (j,1,n) if (!vis[j]) if (MI(w[j],v[k][j]-M*c[k][j])) rv[j] = v[k][j];/// } return sumv*M/sumc;/// return minf; } int main() { int i, j; double L, M, R; double maxv, maxc, minv, minc; while (scanf("%d", &n)!=EOF && n) { Rep (i,1,n) scanf("%d%d%d", &x[i], &y[i], &h[i]); maxv = maxc = -infi, minv = minc = infi; rep (i,1,n) Rep (j,i+1,n) { c[i][j] = c[j][i] = sqrt(sqr((double)x[i]-x[j])+sqr((double)y[i]-y[j])); v[i][j] = v[j][i] = abs((double)h[i]-h[j]); MA(maxv,v[i][j]), MI(minv,v[i][j]); MA(maxc,c[i][j]), MI(minc,c[i][j]); } L = minv/maxc, R = maxv/minc; while (true) {/// R = prim(L);/// if (fabs(L-R) < eps) break;/// L = R;/// }/// /*while (R-L > 1E-6) { // L:minf>0 R:minf<=0 M = (L+R)/2.0; if (prim(M) > eps) L = M; else R = M; }*/ printf("%.3f\n", R); } //END: getchar(), getchar(); return 0; }
Desert King(01分数规划问题)(最优斜率生成树)
标签:inter people engine ESS dig targe proc 0-1分数规划 lin
原文地址:https://www.cnblogs.com/DWVictor/p/11231535.html