POJ 1018 Communication System(贪心+优化)

来源:互联网 发布:公共科目大数据贵州 编辑:程序博客网 时间:2024/06/05 15:10

题目描述:有n种仪器,第i种仪器有m_i个供应商,不同供应商提供的同一种仪器有不同的带宽(B)和价格(p), n种仪器总带宽为所有仪器带宽最小值。要求从每种仪器的供应商中选一个,使得最终总带宽除以总价格最小。

限制:n<=100, m_i<=100

思路:网上说这是一个DP。如果给出了带宽的范围则可以用DP做,但是题目中并没有给出上界。我的做法是从所有仪器中选出一个,用它的带宽作为所有仪器的瓶颈,然后从带宽更大的仪器中每种仪器各选一种,使得总价格最小。显然这时只需要选出每种仪器中带宽比当前瓶颈更大且价格最低的一个。

所以可以对所有仪器进行排序(NlogN, N=10^4=sum_i=1^n(m_i)),带宽小者先,相同带宽低价者先。然后维护一个n元的下标数组index[],index[i]表示第i种仪器中带宽比当前的瓶颈大而价格最低的下标。每次计算 带宽/总价,直接对index[]所指n个仪器求和。之后对其中一个index[i]更新。求和时间为n*N=10^6, 更新index[]时间为n*N,因为每一个index[i]扫过N个元素。总复杂度为10^6级别

代码如下:

/*PROG: POJ1018PROB: Greedy*/#include <cstdio>#include <cstring>#include <cstdlib>#include <cassert>#include <vector>#include <algorithm>using namespace std;#define DEBUG 1#define LOG(...) do { if (DEBUG) fprintf(stderr, __VA_ARGS__); } while(0)typedef pair<int, int> ii;typedef vector<ii> vii;struct Dev {int b, p, id;Dev(int b, int p, int id): b(b), p(p), id(id) {}bool operator<(const Dev& rhs) const {return b < rhs.b || (b==rhs.b&&p<rhs.p);}};int main(void) {int Z; scanf("%d", &Z);while (Z--) {int n; scanf("%d", &n);vector<Dev> dev;vector<int> index(n, -1);for (int i = 0; i < n; ++i) {int m; scanf("%d", &m);for (int j = 0; j < m; ++j) {int b, p; scanf("%d%d", &b, &p);dev.push_back(Dev(b, p, i));}}sort(dev.begin(), dev.end());int uninit = n;for (int i = 0; i < dev.size(); ++i) {int id = dev[i].id;if (index[id]!=-1) continue;index[id] = i, --uninit;if (!uninit) break;}double ans = 0.0;for (int i = 0; i < dev.size(); ++i) {int B = -1, P = 0;for (int j = 0; j < n; ++j) {P += dev[index[j]].p;if (B<0||B>dev[index[j]].b)B = dev[index[j]].b;}if (((double)B)/P>ans) ans = (double)B/P;int id = dev[i].id;int k = index[id]+1;bool found = false;while (k < dev.size()) {if (dev[k].id==id) {found = true; index[id] = k; break;}++k;}if (!found) break;}printf("%.3f\n", ans);}return 0;}


0 0
原创粉丝点击