专题:01分数规划
普通的01分数规划
大意:给定A数组B数组,从中选择N-K个使得R最大,输出Round(100*R);
#include <iostream> #include <algorithm> #include <cmath> #include <cstdio> using namespace std; const int N = 1009; const double Eps = 1e-7; int n, k; double a[N], b[N]; double l, r, mid; int main() { while ( scanf ( "%d %d", &n, &k ) != EOF ) { if ( n == 0 && k == 0 ) break; for ( int i = 1; i <= n; ++i ) { scanf ( "%lf", &a[i] ); } for ( int i = 1; i <= n; ++i ) { scanf ( "%lf", &b[i] ); } l = 0., r = 1.; double t[N], sum; while ( fabs ( r - l ) > Eps ) { sum = 0; mid = 1.* ( l + r ) / 2; for ( int i = 1; i <= n; ++i ) { t[i] = 1.*a[i] - mid * b[i]; } sort ( t + 1, t + 1 + n ); for ( int i = k + 1; i <= n; ++i ) { sum += t[i]; } if ( sum > 0 ) { l = mid; } else { r = mid; } } printf ( "%.0f\n", 100 * l ); } }
最优比率生成树
大意:给定一张图,每条边有一个收益值和一个花费值,求一个生成树,要求花费/收益最小,输出这个值
#include <iostream> #include <algorithm> #include <cmath> #include <cstdio> using namespace std; const int N = 1009; const double Eps = 1e-4; int n, k; double x[N], y[N], h[N]; double dis[N][N], dh[N][N]; double prim ( double k ) { int vis[N] = {0, 1}, s = 1, u = 1, v; double c[N], sum = 0.; while ( s < n ) { double tem = 0x7fffffff; for ( int i = 1; i <= n; ++i ) { if ( !vis[i] ) { double bit = dh[u][i] - k * dis[u][i]; if ( bit < c[i] || u == 1 ) { c[i] = bit; } if ( tem > c[i] ) { tem = c[i]; v = i; } } } sum += c[v]; vis[v] = 1; u = v; ++s; } return sum; } int main() { while ( scanf ( "%d", &n ) != EOF ) { if ( n == 0 ) break; for ( int i = 1; i <= n; ++i ) { scanf ( "%lf %lf %lf", &x[i], &y[i], &h[i] ); } for ( int i = 1; i <= n; ++i ) { for ( int j = i + 1; j <= n; ++j ) { dis[i][j] = dis[j][i] = sqrt ( ( x[i] - x[j] ) * ( x[i] - x[j] ) + ( y[i] - y[j] ) * ( y[i] - y[j] ) ); dh[i][j] = dh[j][i] = fabs ( h[i] - h[j] ); } } double l = 0., r = 10000.0; while ( fabs ( r - l ) > Eps ) { double mid = ( l + r ) / 2; if ( prim ( mid ) >= 0 ) l = mid; else r = mid; } printf ( "%0.3f\n", l ); } }
#include <iostream> #include <algorithm> #include <cmath> #include <cstdio> using namespace std; const int N = 1009; const double Eps = 1e-4; int n, k; double x[N], y[N], h[N]; double dis[N][N], dh[N][N]; double prim ( double k ) { int vis[N] = {0, 1},pos[N]={0}, s = 1, u = 1, v; double c[N]; double cost = 0., len = 0.; while ( s < n ) { double tem = 0x7fffffff; for ( int i = 1; i <= n; ++i ) { if ( !vis[i] ) { double bit = dh[u][i] - k * dis[u][i]; if ( u == 1 || bit < c[i] ) { c[i] = bit; pos[i]=u; } if ( tem > c[i] ) { tem = c[i]; v = i; } } } cost += dh[pos[v]][v], len += dis[pos[v]][v]; vis[v] = 1; u = v; ++s; } return cost / len; } int main() { while ( scanf ( "%d", &n ) != EOF ) { if ( n == 0 ) break; for ( int i = 1; i <= n; ++i ) { scanf ( "%lf %lf %lf", &x[i], &y[i], &h[i] ); } for ( int i = 1; i <= n; ++i ) { for ( int j = i + 1; j <= n; ++j ) { dis[i][j] = dis[j][i] = sqrt ( ( x[i] - x[j] ) * ( x[i] - x[j] ) + ( y[i] - y[j] ) * ( y[i] - y[j] ) ); dh[i][j] = dh[j][i] = fabs ( h[i] - h[j] ); } } double ans = 0., k; while ( 1 ) { k = prim ( ans ); if ( fabs ( k - ans ) < Eps ) break; ans = k; } printf ( "%0.3f\n", ans ); } }
最优比率环
大意:给定一张图,边上有花费。求一个环使得收益和/花费和最大,输出这个比值。
按照前两题的模式,应该是要求∑(a[i]-k*b[i])在一个合法解中的值。
接下来的的问题是如何求合法解,即环。假设我们将单向边对应的花费和收益对应起来,将边权更新为-(a[i]-k*b[i]),那么我们可以通过判断负环的存在判断是否存在f[k]<0.
根据这个性质就可以进行二分了。
#include <iostream> #include <algorithm> #include <cmath> #include <cstring> #include <queue> #include <stack> #include <cstdio> using namespace std; const int N = 5009; const double Eps = 1e-3; int n, m; int u[N], v[N], w[N], val[N]; double rat[N]; double dis[N]; bool BF ( double k ) { int flag ; for ( int i = 1; i <= m; ++i ) rat[i] = k * w[i] - val[v[i]]; for ( int i = 1; i <= n; ++i ) dis[i] = 0; for ( int i = 1; i <= n; ++i ) { flag = 0; for ( int j = 1; j <= m; ++j ) { if ( dis[u[j]] + rat[j] < dis[v[j]] ) { dis[v[j]] = dis[u[j]] + rat[j]; flag = 1; } } if ( !flag ) return 0; } return 1; } int main() { scanf ( "%d %d", &n, &m ); for ( int i = 1; i <= n; ++i ) { scanf ( "%d", &val[i] ); } for ( int i = 1; i <= m; ++i ) { scanf ( "%d %d %d", &u[i], &v[i], &w[i] ); } double l = 0., r = 20000; while ( fabs ( r - l ) > Eps ) { double mid = ( r + l ) / 2; if ( BF ( mid ) ) l = mid; else r = mid; } printf ( "%.2f\n", l ); }