昨天在topcoder的网站上看到关于TCHS32 的解题报告,前2题很简单,关键是第三题SuperPasture,此题分数最高1000,时间有限。于是我也试着做了一下,调试花了N长时间
以下是我翻译的题目:
Farmer Brown 有很多方形的牧地(pasture)。当2个牧地共享一条边时我们说这2个牧地是连接起来的(2个牧地只共享个顶点时,这2个牧地不是连接起来的)。一个super pasture是有连接起来的牧地组成的最大的集合(也是一个方形)。也就是说,对于一个super pasture中的任意2牧地,存在一个连接的通路来连接这2个牧地,并且这条通路不会离开这个super pasture。如果一个牧地没有与任何其它的牧地相连接,那么我们说这个牧地本身就是一个super pasture。
上图含有9个牧地,组成了3个super pasture,牧地1,2,3,5,7组成了一个super pature.注意牧地0和牧地6没有连接起来因为他们仅仅只共享了一个角(corner)。
一个super pasture的badness是这个super pasture的面积减去这个区块中所有牧地的面积和的差。比如,如果一个super pasture仅仅有一个牧地组成,那么它的badness就为0. 上图中3个super pasture的badness 分别为0,10,5
Farmer Brown现在决定卖掉一个牧地,他按照下面的规则来选择卖出的牧地:
1.这个牧地必须属于badness最大的super pasture,如果有多个这样的super pasture,那么要对每个这样的super pasture进行一下的规则.
2.当把这个牧地卖掉之后,不能使包含这个牧地的super pasture分裂成开
3.在所有满足1,2条件的牧地中,他将选择面积最小的牧地,如果有多个这样的牧地,那么他将选择序号最小的牧地
给你一个字符串数组pastures(String[] pastures),其中包含Farmer Brown拥有的牧地的信息。数组中的每个元素都是这样的格式"a b c d",其中a b c d分别代表牧地的最左边,最右边(比真实的大1),最上边,最下边(比真实的大1)的坐标。也就是说,这个方块牧地可以用2个坐标来表示(a,c)和(b-1,d-1)。你的程序返回的牧地编号必须是从下表为0开始的结果。
定义:
类: SuperPasture
方法: whichOne
参数: String[]
返回: int
方法签名: int whichOne(String[] pastures) (请保证你的方法是public的)
注意:
1.pastures包含的元素的个数在0到50之间
2.每个元素的格式是"a b c d",其中a b c d 是0到1000的整数
3.保证没有2个牧地是相交的
例子:
0):
{"1 3 1 4", "5 7 1 3", "7 8 1 5", "8 10 4 5", "5 6 5 7", "9 10 0 1", "3 5 4 7", "8 10 1 3", "1 3 5 6"}
你的程序必须返回:5
这个例子就代表上图,应用题目所述的规则:
1。3个super pasture分别含有的badness为0,10,5,所有选择第2块super pasture
2。由于卖掉的牧地后不能使该super pasture分裂开,所有不能卖牧地2和7
3。现在在牧地1,3,5种选择,由于5的面积最小为1,所以他最终选择卖5号牧地
1): {"4 6 1 5", "1 6 5 7", "8 13 1 3", "8 10 3 7"}
你的程序必须返回:0
2): {"0 100 0 100", "500 511 500 509", "710 720 710 720"}
你的程序必须返回:1
3): {"0 1 1 2", "0 1 2 3", "0 1 3 4", "0 1 0 1"}
你的程序必须返回2
4): {"0 1 1 2", "0 1 2 3", "0 2 3 4", "0 1 0 1"}
你的程序必须返回3
解题思路:
首先要明确根本不需要将整个地图存起来,因为整个地图大小为1000*1000,内存开销大而且这样做来遍历地图耗时间。由于题目说任意2个牧地没有相交的,我们可以将一个牧地当作一个点来存储,在我的代码中为类Pasture,这样最多只要存储50个就够了。判断2个牧地是否相邻比较简单,直接看我的代码里面的。所以我们很容易建立连接表connect_list。现在的任务是要确认整个地图中有多少个super pasture,并且每个super pasture含有哪些牧地,我们用一个数组block[50]来表示super pasture,block[i]表示第i个牧地,它的数据类型为类Block,其中的成员list包含这个super pasture中的所有的牧地。有了这些,我们就很容易来求了,大家应该知道种子染色法吧,就是在地图中随便丢一种颜色的种子,让它自由扩散到相邻的区域并且给那些区域染相同的颜色,由于已经建立了连接表connect_list,所有用dfs遍历就可以轻松解决。
最后就是求出含有最多badness的集合,然后从这个里面选出合适的牧地来卖。
关于规则中的卖掉一个牧地后不能让该super pasture破裂,这个也很容易实现。假如我们现在要看牧地i是否能买,connect_list[i].list中的全部都是与这个牧地相连的牧地号,所以也属于这个区域,如果这些牧地里面有一个目j,与它相连的牧地数connect_list[j].size为1,既只与i相连,那么把i卖掉后这个区域很定会被破裂,因为j原来属于这个区域,而卖掉i后,j就不属于这个区域了,即分裂了出去。
恩,原理都讲清楚了,下面是我的实现的代码:
1
#include
<
iostream
>
2
#include
<
string
>
3
#include
<
vector
>
4
#include
<
sstream
>
5
using
namespace
std;
6

7
//
表示牧地的类
8

class
Pasture
{
9
public:
10
int x1,y1,x2,y2;
11
12
Pasture(int xx1,int yy1,int xx2,int yy2) :x1(xx1),y1(yy1),x2(xx2),y2(yy2)
{}
13
int area()
{
14
if(x1==x2)
15
return y2-y1+1;
16
if(y1==y2)
17
return x2-x1+1;
18
return (x2-x1+1)*(y2-y1+1);
19
}
20
21
virtual ~Pasture()
{}
22
}
;
23

24
//
表示区块的类 即SuperPasture,继承自Pasture
25

class
Block :
public
Pasture
{
26
int fill;
27
public:
28
vector<int> list; //区块中含有的pasture的序号列表
29
30
Block() : fill(0),Pasture(9999,9999,0,0)
{}
31
//向区块中加入序号为index的pasture
32
void set(int index,int xx1,int yy1,int xx2,int yy2)
{
33
if(x1>xx1) x1=xx1;
34
if(x2<xx2) x2=xx2;
35
if(y1>yy1) y1=yy1;
36
if(y2<yy2) y2=yy2;
37
if(xx1==xx2)
38
fill+=yy2-yy1+1;
39
else if(yy1==yy2)
40
fill+=xx2-xx1+1;
41
else
42
fill+=(xx2-xx1+1)*(yy2-yy1+1);
43
list.push_back(index);
44
}
45
int badness()
{
46
return area()-fill;
47
}
48
}
;
49

50
//
用来表示pasture连接关系的类
51

class
Connect
{
52
public:
53
vector<int> list; //连接表
54
int size()
{
55
return list.size();
56
}
57
void push_back(int i)
{
58
list.push_back(i);
59
}
60
}
;
61

62

class
SuperPasture
{
63
vector<Pasture> pasture; //牧地类
64
vector<Connect> connect_list; //连接表
65
Block block[50]; //区块(最多50个)
66
int total_super; //区块的个数
67
bool mark[50]; //用于dfs遍历的标志数组
68
69
bool connect(int,int); //判断2个区块是否相邻
70
void dfs(int,int); //多地图进行dfs遍历
71
bool cansell(int); //判断某个pasture是否可以卖出去
72
73
public:
74
SuperPasture()
{
75
total_super=0;
76
memset(mark,0,sizeof(mark));
77
}
78
int whichOne(vector<string>);
79
}
;
80

81

bool
SuperPasture::connect(
int
i,
int
j)
{
82
bool connect_top_bottom=( abs(pasture[i].x2-pasture[j].x1)==1
|| abs(pasture[i].x1-pasture[j].x2)==1 );
83
bool connect_right_left=( abs(pasture[i].y2-pasture[j].y1)==1
|| abs(pasture[i].y1-pasture[j].y2)==1 );
84
if( connect_top_bottom
&& (pasture[i].y1>=pasture[j].y1&&pasture[i].y1<=pasture[j].y2)
85
|| connect_top_bottom
&& (pasture[i].y2>=pasture[j].y1&&pasture[i].y2<=pasture[j].y2)
86
|| connect_right_left
&& (pasture[i].x1>=pasture[j].x1&&pasture[i].x1<=pasture[j].x2)
87
|| connect_right_left
&& (pasture[i].x2>=pasture[j].x1&&pasture[i].x2<=pasture[j].x2) )
88
return true;
89
return false;
90
}
91

92

void
SuperPasture::dfs(
int
i,
int
index)
{
93
if(!mark[i])
{
94
mark[i]=true;
95
//向区块index中添加该pasture
96
block[index].set(i,pasture[i].x1,pasture[i].y1,pasture[i].x2,pasture[i].y2);
97
for(int j=0;j<connect_list[i].size();j++)
98
dfs(connect_list[i].list[j],index);
99
}
100
}
101

102

bool
SuperPasture::cansell(
int
k)
{
103
for(int i=0;i<connect_list[k].size();i++)
{
104
int connect_id=connect_list[k].list[i];
105
if(connect_list[connect_id].size()==1)
106
return false;
107
}
108
return true;
109
}
110

111

int
SuperPasture::whichOne(vector
<
string
>
pastures)
{
112
int i,j;
113
vector<int> tot_max_badness; //含有badness最大的区块的集合(这样的区块可能有很多)
114
115
//读入数据,初始化pasture和connect_list
116
for(i=0;i<pastures.size();i++)
{
117
istringstream is(pastures[i].c_str());
118
int a,b,c,d;
119
is>>a>>b>>c>>d;
120
pasture.push_back(Pasture(c,a,d-1,b-1));
121
connect_list.push_back(Connect());
122
}
123
124
//建立连接表
125
for(i=0;i<pasture.size();i++)
126
for(j=0;j<pasture.size();j++)
127
if(i!=j&&(connect(i,j)||connect(j,i)))
128
connect_list[i].push_back(j);
129
130
//进行dfs遍历,并建立block相关信息
131
for(i=0;i<pasture.size();i++)
132
if(!mark[i])
133
dfs(i,++total_super);
134
135
//求出含有badness最多的区块的集合
136
tot_max_badness.push_back(1);
137
for(i=1;i<=total_super;i++)
{
138
if(block[i].badness() >= block[tot_max_badness.back()].badness())
{
139
if(block[i].badness()>block[tot_max_badness.back()].badness())
140
tot_max_badness.clear();
141
tot_max_badness.push_back(i);
142
}
143
}
144
145
int sell=block[tot_max_badness[0]].list[0];
146
for(i=0;i<tot_max_badness.size();i++)
{
147
int max_badness=tot_max_badness[i];
148
for(j=0;j<block[max_badness].list.size();j++)
{
149
int sell_id=block[max_badness].list[j];
150
if(cansell(sell_id))
{
151
if(!cansell(sell))
152
sell=sell_id;
153
if(pasture[sell_id].area()<pasture[sell].area())
154
sell=sell_id;
155
if((pasture[sell_id].area()==pasture[sell].area())&&sell_id<sell)
156
sell=sell_id;
157
}
158
}
159
}
160
return sell;
161
}
162
测试一样
int main(){
vector<string> p;
p.push_back("0 1 1 2");
p.push_back("0 1 2 3");
p.push_back("0 2 3 4");
p.push_back("0 1 0 1");
SuperPasture s;
cout<<s.whichOne(p);
return 1;
}