今天下午无聊,花了1个多小时,做了下USACO中MilkCow这题。初看这题感觉似乎挺难的,求的是最值,莫非用DP?仔细想下,发现并不涉及什么高深的算法,解决这题的关键在于编程的相关技巧。
按人类的思维,解决这题非常简单,就是合并各个时段,求取极值即可。那么按计算机该怎么做呢?很简单也是这几步,只是把人类合并集合的步骤展开来罢了(计算机可没这么聪明。。。)
讨论程序首先要看的是数据结构,它关系着算法的效率以及对算法的理解。我这里用的是很简单的数据结构---low和high这两个数组,他们分别存储各个时段的下限和上限值。具体的步骤如下:
1 对各个集合按下限值进行排序(上限值作为卫星数据),这里用的是插入排序,因为感觉数据量不是很大(5000个数据),还有就是很有可能大部分都是排好序的数据,用快排可能会退化。
2 合并各集合,这里用到了两个指针i、j,分别指向待合并的集合以及将要被合并的集合,为了节省存储空间,我这里把被合并掉的集合的low和high的相应项都设为0,方便在解决求最值的问题。
3 求取最值,这里比较简单就不赘述了。
简单的思想就是如此,这也是这题官方答案的第一种思路,好了,上代码:
Milking Cow
1 /*
2 ID: happyan3
3 PROG: milk2
4 LANG: C++
5 */
6
7 #include <iostream>
8 #include <fstream>
9 #include <cassert>
10
11 using namespace std;
12
13 int N;
14 unsigned int* low = NULL;
15 unsigned int* high = NULL;
16
17 void sort(void); // use insertion sort
18 void Merge(void);
19 unsigned int FindLongestMilked(void);
20 unsigned int FindLongestNoMilked(void);
21
22 int main(void)
23 {
24 ifstream milk2In;
25 milk2In.open("milk2.in");
26
27 milk2In>>N;
28
29 low = new unsigned int[N];
30 high = new unsigned int[N];
31
32 for(int i=0; i < N; i++)
33 {
34 milk2In>>low[i]>>high[i];
35 }
36
37 sort();
38 Merge();
39
40 int nLongestMilked = FindLongestMilked();
41 int nLongestNoMilked = FindLongestNoMilked();
42
43 ofstream milk2Out;
44 milk2Out.open("milk2.out");
45
46 milk2Out<<nLongestMilked<<" "<<nLongestNoMilked<<endl;
47
48 delete [] low;
49 delete [] high;
50 milk2In.close();
51 milk2Out.close();
52 return 0;
53 }
54 void sort(void)
55 {
56 int keyLow = 0;
57 int keyHigh = 0;
58 int i = 0;
59 for(int j=1; j < N; j++)
60 {
61 keyLow = low[j];
62 keyHigh = high[j];
63
64 i = j-1;
65 while(i >= 0 && low[i] > keyLow)
66 {
67 low[i+1] = low[i];
68 high[i+1] = high[i];
69 i = i-1;
70 }
71 low[i+1] = keyLow;
72 high[i+1]=keyHigh;
73 }
74 }
75
76
77 void Merge(void)
78 {
79 int i = 0;
80 int j = 1;
81 while (i < N && j < N)
82 {
83 if(high[i] < low[j]) //无法合并
84 {
85 i = j;
86 j++;
87 }
88 else
89 {
90 if(high[i] >= high[j]) //可全部包含在内
91 {
92 low[j] = 0; // 设置标志表示已被合并
93 high[j] = 0;
94 }
95 else //原上限小于被合并时段上限,求并集
96 {
97 high[i] = high[j];
98 low[j] = 0;
99 high[j] = 0;
100 }
101 j++;
102 }
103 }
104
105 }
106
107
108
109
110 unsigned int FindLongestMilked(void)
111 {
112 unsigned int res = 0;
113
114 int interval = 0;
115 for(int i=0; i < N; i++)
116 {
117 interval = high[i] - low[i];
118 if(res < interval)
119 res = interval;
120 }
121
122 return res;
123 }
124
125
126 unsigned int FindLongestNoMilked(void)
127 {
128 unsigned int res = 0;
129
130 int interval = 0;
131
132 int i=0;
133 int j=1;
134 while(i < N && j < N)
135 {
136 if(0 == high[i])
137 {
138 i=j;
139 j++;
140 }
141 else
142 {
143 if(0 == low[j])
144 {
145 j++;
146 }
147 else //两者都不为0
148 {
149 interval = low[j] - high[i];
150 if(res < interval)
151 res = interval;
152 i=j;
153 j++;
154 }
155 }
156 }
157
158 return res;
159 }
160