Topcoder->TCHS32 SuperPasture

昨天在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  {
  9public:
 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;
 27public:
 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  {
 52public:
 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
 73public:
 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;
}

你可能感兴趣的:(topcoder)