给定整数序列a,b,求出下式的最大值
sum{ai*xi}/sum{bi*xi},xi=0|1
通俗来说,就是选出一些整数对(ai,bi),使得选出的a之和与选出的b之和商最大化
二分答案L,即选出的a之和与b之和的商是L
判断L是否成立,只要判断是否存在sum{ai-L*bi}>0即可
poj2728为要找出各边收益除以各边成本的最大生成树
那么二分商L,另边权变成ai-L*bi求最大生成树,如果和>0,答案可行
#include <iostream> #include <string> #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #include <cmath> #define MAXN 1005 #define INF 1000000000 #define eps 1e-7 using namespace std; int n; double Edge[MAXN][MAXN],lowcost[MAXN]; int v[MAXN]; struct Point{int x, y, z;}p[MAXN]; double cal(int a, int b) { return sqrt(1.0 * (p[a].x - p[b].x) * (p[a].x - p[b].x) + 1.0 * (p[a].y - p[b].y) * (p[a].y - p[b].y)); } double prim(double l)//总成本是否可以小于总长度*l ,即cost-l*len>=0,那么cost/len>=l,l得变大 { double cost = 0, len = 0; double sum = 0; for(int i = 1; i <= n; i++) { v[i] = 0; lowcost[i] = -l*abs(p[1].z - p[i].z) + Edge[1][i]; } v[1] = 1; for(int i = 1; i < n; i++) { double mx = -INF; int x = 0; for(int j = 1; j <= n; j++) if(v[j] != 1 && lowcost[j] > mx){ x = j; mx = lowcost[j]; } v[x] = 1; sum += lowcost[x]; for(int j = 1; j <= n; j++) { double tmp = -l*abs(p[x].z - p[j].z) + Edge[x][j]; if(v[j] != 1 && tmp > lowcost[j]) lowcost[j] = tmp; } } if(sum>=0)return 1; return 0; } int main() { while(scanf("%d", &n) != EOF && n) { for(int i = 1; i <= n; i++) scanf("%d%d%d", &p[i].x, &p[i].y, &p[i].z); for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) Edge[i][j] = cal(i, j); double l = 0.0, r = 100.0, mid,ans; while(r - l > 0.0000001) { mid = (l + r) / 2; if(prim(mid)) l = mid,ans=mid; else r = mid; } printf("%.3f ", 1/ans); } return 0; }