USACO习题:Milking Cows

这道题目,给你一组时间范围,求最大的时间跨度和最大的时间段间隔。题目看似挺简单,但是如果不加考虑却会发现其中对于时间间隔的处理,有多种情况。也就是会所程序里可能会出现出多的判断语句,使得代码变得非常难写而且容易出错。

 

我的第一版解法

我采用了一种比较奇怪的数据结构,就是将链表和线性表结合。线性表用于表示一条时间轴,链表用于表示不同时间的跨度。

以样例数据为例

300 1000
700 1200
1500 2100

 我先不论时间的起点和终点,将他们一并放在一个数轴上,然后排序,得到一个时间轴。

300     700     1000     1200     1500     2100

 这是第一步处理,我的第二部处理是遍历这个时间轴,如果某个数值是一个时间的起点,那么拿到他的终点。从这个起点建立链表到他的终点。

比如时间段300,1000。我的程序会这样处理

300 --> 700 --> 1000

 然后再到700,在从700连到1200,再1500(1000是一个时间段终点)全部做好以后,一个时间段就成了一个链表:

300 --> 700 --> 1000 --> 1200     1500 --> 2100

 时间段跨度最长的链条就是所求的(不一定是链表长度最长的)。

 

这个解法的好处就是对于时间跨度的交叉不需要任何判断,只要把它们串起来,相当于在数轴上不停的涂颜色,最后找到最大的一块颜色。

但是缺点就是,建立链表的步骤,他的最差情况的复杂度是O(n^2),如下情况出现

100 1000
200 900
300 800
400 700
500 600

 不过,数据大多数情况下比较随机,所以我个人估计平均每个时间段的跨度也在logn左右,所以这个代码实际在测试的时候跑得还是非常快的。

View Code
  1 #include <iostream>
2 #include <fstream>
3 #include <string>
4 #include <map>
5 #include <vector>
6 #include <algorithm>
7
8
9 using namespace std;
10
11 struct Node {
12 int value;
13 struct Node *next;
14 Node(int value) { this->value = value;this->next=NULL;}
15 };
16
17 void p_axis(vector<Node> &axis){
18 for(int i=0;i<axis.size();++i){
19 cout<<axis[i].value;
20 if(axis[i].next!=NULL)
21 cout<<"-->";
22 else
23 cout<<"";
24 }
25 cout<<endl;
26 }
27
28 bool node_cmp(Node n1,Node n2) {
29 return n1.value < n2.value;
30 }
31
32 int index(vector<Node> &axis, int value){
33 for(int i=0;i<axis.size();++i)
34 if (axis[i].value==value)
35 return i;
36 return -1;
37 }
38
39
40 int main() {
41 ofstream fout("milk2.out");
42 ifstream fin("milk2.in");
43
44 int len =0;
45 fin>>len;
46
47 map<int,int> pairs;
48 vector<Node> node_axis;
49
50 int start=0,end=0;
51 map<int,int>::iterator iter;
52 for(int i=0;i<len;++i){
53 fin>>start>>end;
54 iter = pairs.find(start);
55 if(iter==pairs.end()){
56 pairs[start] = end;
57 }else{
58 pairs[start] = max(pairs[start],end);
59 }
60 node_axis.push_back(Node(start));
61 node_axis.push_back(Node(end));
62 }
63
64 //printf("len:%d,node_axis:%d,map:%d\n",len,node_axis.size(),pairs.size());
65 sort(node_axis.begin(),node_axis.end(),node_cmp);
66
67 //p_axis(node_axis);
68
69
70 for(int i=0;i<node_axis.size();++i){
71 Node *cur = &node_axis[i];
72
73 int value = cur->value;
74
75 map<int,int>::iterator iter = pairs.find(value);
76 if(iter==pairs.end())
77 continue;
78 //cout<<i<<":"<<"start:"<<value<<",end:"<<(*iter).second<<endl;
79
80 int end = (*iter).second;
81 int j=i;
82 do{
83 ++j;
84 cur->next = &node_axis[j];
85 cur = &node_axis[j];
86 }while(node_axis[j].value!=end);
87 }
88
89 //p_axis(node_axis);
90
91 int max_mk=0,max_nomk=0,i=0;
92
93 Node *end_node =NULL;
94 while (i<node_axis.size()){
95 Node *start = &node_axis[i];
96 if(end_node){
97 int no_interval = start->value - end_node->value;
98 max_nomk = no_interval>max_nomk?no_interval:max_nomk;
99 }
100
101 end_node = start;
102 while(end_node->next!=NULL){
103 end_node = end_node->next;
104 i+=1;
105 }
106 int interval = end_node->value - start->value;
107 max_mk = interval>max_mk?interval:max_mk;
108
109 i+=1;
110 }
111
112 fout<<max_mk<<" "<<max_nomk<<endl;
113
114
115 fin.close();
116 fout.close();
117 return 0;
118 }



 

改进版解法

解决以后看到分析的上面的提示,突然想到,其实在排序以后,已经时合并变得非常容易。思路如下:

1。先将给定的时间段按照【初始时间排序】

2。从最左边开始遍历,每次取相邻的两个时间段A,B。(注意:B的起始时间已经在A的右边)

  会有以下3种情况

1)我们将A.end更新成为B.end

2)我们另起一个时间段,因为A不需要做合并

3)直接跳过B

 

经过这样的合并遍历,我们就得到了一个已经合并时间段的时间轴,其中每一个时间段都不相交。这样就使我们求值变得非常方便。

代码如下:

View Code
#include <iostream>
#include <fstream>
#include <string>
#include <map>
#include <vector>
#include <algorithm>


using namespace std;

struct Interval {
int start;
int end;
Interval(int start,int end) { this->start=start;this->end=end;}
Interval(const Interval& val) { this->start = val.start;this->end = val.end;}
int span() { return (this->end - this->start);}
};

bool operator<(const Interval& val1,const Interval& val2) { return val1.start < val2.start;}



int main() {
ofstream fout("milk2.out");
ifstream fin("milk2.in");

int len =0;
fin>>len;

vector<Interval> node_axis;

int start=0,end=0;
for(int i=0;i<len;++i){
fin>>start>>end;
node_axis.push_back(Interval(start,end));
}

//printf("len:%d,node_axis:%d,map:%d\n",len,node_axis.size(),pairs.size());
sort(node_axis.begin(),node_axis.end());

//p_axis(node_axis);
//add a sentinel
node_axis.push_back(Interval(655534,655535));

vector<Interval> combined_axis;
Interval max_interval = node_axis[0];
for(int i =1 ; i<node_axis.size();++i){
if(node_axis[i].start > max_interval.end){
combined_axis.push_back(max_interval);
max_interval = node_axis[i];
}else if(node_axis[i].end > max_interval.end){
max_interval.end = node_axis[i].end;
}else{
//filter this interval
continue;
}
}

int max_mk = combined_axis[0].span(),max_nomk=0;
for(int i =1;i<combined_axis.size();++i){
max_mk = max(combined_axis[i].span(),max_mk);
max_nomk = max((combined_axis[i].start - combined_axis[i-1].end),max_nomk);
}

fout<<max_mk<<" "<<max_nomk<<endl;


fin.close();
fout.close();
return 0;
}



posted on 2012-03-21 11:41  lzyzizi  阅读(203)  评论(0编辑  收藏  举报

导航