posts - 10,  comments - 14,  trackbacks - 0
昨天做了道贪心的题,最近都在做这个,今天先写下这题的报告。
题目:
http://acm.pku.edu.cn/JudgeOnline/problem?id=1230

其实如果掌握了动态规划的方法,那对于贪心就只要找到它的贪心性质就可以了,因为贪心也要求最优子结构,找最优子结构的方法和动态规划一样,即要找到对于一个问题,它的最优解包含了其子问题的最优解(对了,前面说要总解动态规划的,一直没总结,这类题的确很多,也很关键)。贪心性质简单讲就是一个全局最优解可以通过局部最优选择来达到,就是步步都选择当前最优的情况。
对于这道题,首先是建模,怎样读入题目的信息,我并没有把整个图都用矩阵表示,而是自建了个数据结构row,其属性包括rid(行号),left(左边界),right(右边界);然后用vector把它们一个个读入的,这样既省了空间也省了时间,再用一个column数组存储每个列所占的墙数。这样的存储就已经满足我的算法了。下面是贪心部分,首先是最优子结构,设Sj 为从第0行到第j行为达满足条件而要删去的最小墙数,那么Sj=Sj-1+N其中Nj为为满足第j列墙数不大于k删去的最小墙数,Nj =Cj - k (when Cj > k  ) or Nj = 0; 其中Cj为第为j列当前的墙数(即在前面j-1列删除了墙之后)。下面对N加以说明,显然要使它尽可能的小就要使Cj 尽可能的小,所以在删除第j列之前的删除工作要尽量的删除右边界大的墙,也就是对于第j列选择删除墙时也要选择右边界大的墙删除得到N
我们来证明这样的Sj具有最优子结构性质,即若Sj最优Sj-1也最优。
假设Sj-1不是最优的,那设存在T<Sj-1,因为根据Nj 的选择规则其大小是一定的,所以T+Nj <Sj-1+N=Sj,即存在有比Sj更优的方案,这与Sj最优矛盾,所以若Sj最优Sj-1也最优的。
那么根据Nj 的选择方式就可知其满足贪心性质,每次贪心的选择右边界最大的墙删除保证当前列满足条件。
这样算法就出来了,即从下标为0的列从左到右扫描到下标最大的列,对每一列循环操作至这一列的墙数不大于k,循环中每一次操作找右边界最大的墙删除即可。
这题还有一些小细节:
1.题目可能给出的第一个列坐标比第二个大,要判断下;
2.一行可能有多个墙(这个直接影响了算法,不然会有更简单的贪心方法)。
代码如下:
#include<iostream>
using namespace std;
#include
<vector>
struct row{
    
int rid;
    
int left;
    
int right;
};
int column[110];
vector
<row> wall;
int main()
{
    
int c,n,k,count=0;
    scanf(
"%d",&c);
    
while(c--)
    {
        count
=0;
        
int maxc=0;
        scanf(
"%d%d",&n,&k);
        
while(n--)
        {
            
int ux,uy,dx,dy;
            scanf(
"%d%d%d%d",&ux,&uy,&dx,&dy);
            
if(ux>dx)
            {
                ux
=ux+dx;
                dx
=ux-2*dx;
                dx
=(ux+dx)/2;
                ux
=ux-dx;

            } 
            
if(dx>maxc)
                maxc
=dx;
            row temp;
            temp.rid
=uy;
            temp.left
=ux;
            temp.right
=dx;
            wall.push_back(temp);
            
for(int i=ux;i<=dx;i++)
                column[i]
++;
        }
        
int maxv=1;
        
for(int i=0;i<=maxc;i++)
            {
                
while(column[i]>k)
                {
                    vector
<row>::iterator it=wall.begin();
                    vector
<row>::iterator iter;
                    maxv
=0;
                    
while(it!=wall.end())
                    {
                        
if((*it).left<=i)
                        {
                            
if((*it).right>maxv)
                            {
                                maxv
=(*it).right;
                                iter
=it;
                            }
                        }
                        it
++;
                    }
                    
for(int i=(*iter).left;i<=(*iter).right;i++)
                    {
                        column[i]
--;
                    }
                    wall.erase(iter);
                    count
++;

                }
            }
        
        printf(
"%d\n",count);
        wall.clear();
        memset(column,
0,sizeof(column));

    }
    
return 0;
}


posted on 2009-06-02 12:31 tortoisewu 阅读(1977) 评论(0)  编辑 收藏 引用

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


<2009年6月>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

常用链接

留言簿(1)

随笔档案

文章分类

搜索

  •  

最新评论

阅读排行榜

评论排行榜