poj1018 Communication System
总结 :
这个题目思路倒是老早就想起来了,但是实现搞得我心力交瘁阿,最终还是用c++完成的,否则要是用c实现的话,一定会写出来一坨屎一样的代码出来。
题目大意:
1
3 <==三种设备
3 100 25 150 35 80 25 <==第一种设备3个供货商,他们提供的设备的带宽和价格依次排列
2 120 80 155 40 <==同上
2 100 100 120 110 <==同上
要用n种(示例中n=3)设备构建一个系统,每个设备有带宽和价格两个属性,而且每种设备都有好多个不一样的供货商,他们提供的设备虽然一样起作用,但是带宽和价格是不同的。
目的就是求出全局带宽(设备中的最小带宽)尽可能大同时总价尽可能小。
算法:
算法类似背包问题,按设备依次枚举所有可能全局带宽带所能获得价格最小值。
定义数组 f[i][j], i 取从 0 到 n-1,j 用来枚举所有的可能的全局带宽。f[i][j] 就保存了讨论前 i 种设备的时候,全局带宽 j 所能达到的总价最小值,拗口。。。
那么,每计算一种设备要考虑3种情况,
第一种是在前一次能达到的全局带宽 j,这次也可能能达到,当然前提是有带宽 >= j的设备
if f[i - 1][j] is inited,f [i - 1][j] += min{price{k} }, bandwidth(k) >= j
第二种是将那些再次出现的全局带宽进行初始化,
我被打败了,太佩服写算法导论的大牛了,那么复杂的算法也能说明白
输入数据
1 3
3 100 25 150 35 80 25
2 120 80 155 40
2 100 100 120 110
(80, 25) (100, 25) (120, 0) (150, 35) (155, 0) //注意已经删除重复并且排序
(80, 65) (100, 65) (120, 115) (150, 75) (155, 0)
(80, 165) (100, 175) (120, 185) (150, 0) (155, 0)
我用debug(i,j),input(i,j)表示dubug矩阵和input矩阵的元素。
1. 对于debug(1, j)就是使用input(1, j)初始化,例如input(1,1):(100,25),我们就知道只考虑第一种设备的时候,带宽100是有可能的,价格是25
2. debug(2,1)和debug(2,2)计算过程类似,首先我们知道debug(1,1)和debug(1,2)是有值的,并且input(2,1)和input(2,2)的带宽都要比他大,那么我们只需要从input(2,1)和input(2,2)这两个设备中选一个便宜的加上即可<<===对比debug(3,4)===>>对于debug(3,4)虽然debug(2,4)有值,但是我们发现第三种设备的带宽只有100和120两种选择,都比debug(3,4)的带宽150小,那么选择到第三种设备的时候就不可能有一种方案达到带宽150
3. debug(2,3)在debug(1,3)是没有值的,但是有输入input(2,1)的带宽是120,所以可以对其进行初始化。怎么初始化呢?我们要看到debug(1,4),debug(1,5)都是带宽比120大,从他们中选小的加上即可
2 #include <cstring>
3
4 class device_node
5 {
6 public:
7 int b;
8 int p;
9
10 device_node(): b(0), p(0){}
11 device_node(int _b, int _p): b(_b), p(_p){}
12 device_node& operator=(const device_node &right)
13 {
14 b = right.b;
15 p = right.p;
16 return *this;
17 }
18 };
19
20 class devices
21 {
22 private:
23 device_node *array;
24 int counter;
25 int num;
26
27 public:
28 devices(): counter(0), num(100)
29 {
30 array = new device_node[102];
31 }
32 devices(int _num): counter(0), num(_num)
33 {
34 array = new device_node[num + 2];
35 }
36 ~devices()
37 {
38 delete[] array;
39 }
40 void init()
41 {
42 counter = 0;
43 memset(array, 0, sizeof(device_node) * (num + 2));
44 }
45 void append(device_node &node, bool multi)//插入排序
46 {
47 if(multi && exist(node.b) != -1)
48 return;
49 int i;
50 for(i = counter++; i >= 0; --i)
51 if(node.b < array[i].b)
52 array[i+1] = array[i];
53 else
54 {
55 array[i+1]=node;
56 break;
57 }
58 }
59 device_node* begin()
60 {
61 return &array[1];
62 }
63 device_node* end()
64 {
65 return &array[counter + 1];
66 }
67 int exist(int b)//某个带宽是否已经插入了
68 {
69 int begin = 1, end = counter + 1;
70 int mid;
71 while(begin != end)
72 {
73 mid = (begin+end)/2;
74 if(array[mid].b > b)
75 end = mid;
76 else if(array[mid].b < b)
77 begin = mid + 1;
78 else
79 break;
80 }
81 if(begin == end)
82 return -1;
83 else
84 return array[mid].p;
85 }
86 int min_p(int b)//找满足条件的最便宜设备
87 {
88 int i;
89 int min = 200000000;
90 for(i = 1; i <= counter; ++i)
91 if(array[i].b >= b && array[i].p && array[i].p < min)
92 min = array[i].p;
93 return (min == 200000000)? -1 : min;
94 }
95 void print()
96 {
97 int i;
98 for(i = 1; i <= counter; ++i)
99 printf("(%d, %d) ", array[i].b, array[i].p);
100 printf("\n");
101 }
102 };
103
104 int main()
105 {
106 int t, n;
107 scanf("%d", &t);
108 devices system[100];
109 devices f(10000);
110 while(t--)
111 {
112 scanf("%d", &n);
113 int i, j;
114 int m, b, p;
115 f.init();
116 for(i = 0; i < n; ++i)
117 {
118 system[i].init();
119 scanf("%d", &m);
120 for(j = 0; j < m; ++j)
121 {
122 scanf("%d %d", &b, &p);
123 device_node tmp1(b, p);
124 system[i].append(tmp1, false);
125 device_node tmp2(b, 0);
126 if(i == 0)
127 f.append(tmp1, true);
128 else
129 f.append(tmp2, true);
130 }
131 }
132 for(i = 0; i < n; ++i)
133 system[i].print();
134 //int pass;
135 //for(pass = 10; pass <= 200; pass += 10)
136 //if(f.exist(pass))
137 // printf("%d pass\n", pass);
138 // else
139 // printf("%d not pass\n", pass);
140 f.print();
141 device_node *iter;
142 for(i = 1; i < n; ++i)
143 {
144 for(iter = f.begin(); iter != f.end(); ++iter)
145 {
146 int exist_p = system[i].exist(iter->b);
147 int system_min_p = system[i].min_p(iter->b);
148 int f_min_p = f.min_p(iter->b);
149 if(iter->p)// 如果已经初始化了(或者说这个全局带宽已经出现过了)
150 {
151 if(system_min_p == -1)//如果没有更大的带宽,那么是这种选法是不可能的
152 iter->p = 0;
153 else
154 iter->p += system_min_p;
155 }
156 if(exist_p != -1 && f_min_p != -1)//有一样的带宽出现了
157 {
158 if(iter->p == 0)
159 iter->p = exist_p + f_min_p;
160 else
161 iter->p = iter->p < exist_p + f_min_p? iter->p : exist_p + f_min_p;
162 }
163 }
164 f.print();
165 }
166 double result = 0;
167 for(iter = f.begin(); iter != f.end(); ++iter)
168 {
169 if(iter->p)
170 {
171 double shang = double(iter->b)/double(iter->p);
172 result = result > shang? result : shang;
173 }
174 }
175 printf("%.3f\n", result);
176 }
177 }
178
179