庆祝下自己完全AC的第一道贪心~~~

来源:互联网 发布:apm飞控用的什么单片机 编辑:程序博客网 时间:2024/04/29 23:20

poj1065:http://acm.pku.edu.cn/JudgeOnline/problem?id=1065

 

从昨天开始做贪心题以来,包括输入输出等问题,完全靠自己AC的第一题哈哈!

 

加上前一道水题,今晚就总共攻克了两道贪心,鼓励一下!

 

我发现贪心中很多题目最后都化归成一个集合中元素的顺序问题,其中每个元素包含两个坐标(往往有头和尾的意思),看上去和活动选择问题有那么点像。

 

看懂题意后首先想到的就是排序,按x排,x相同再按y排,这样排序后的集合有个特性,就是如果某个元素不能接在前面某个元素的后面,那它一定是排头。所以第一个元素肯定是排头。以(1,4),(2,1),(3,5),(4,9),(5,2)为例(已排好序).

先放(1,4).接下来(2,1)不能接在(1,4)后面,于是另起炉灶。当前状态变为(1,4),(2,1)。(3,5)两个都能接,于是接在尾数较大的4后面,为什么?直观上讲因为我们希望队列尾越小越好,如果(3,5)接在(2,1)后面一下子把尾数升了4,比较不利,所以“贪婪”地选择了接在(1,4)后面。(1,4)(3,5),(2,1)-->(1,4)(3,5)(4,9),(2,1)-->(1,4)(3,5)(4,9),(2,1)(5,2)。完毕。其他的例子就仿照此做法即可。

 

下面来证明算法的正确性。

首先,达到(1,4),(2,1)是由条件决定的,没有其他的放置方法。如果再来个(3,3)应该放哪?应该放在(2,1)后面。假设另起炉灶(只剩下这种选择),那么假设最终的最优解为(1,4)xxx,(2,1)yyy,(3,3)zzz,wwww,那么把(3,3)zzz接在(2,1)后面,把yyy另起炉灶也满足条件,并且未增加队列数。因此这是个贪心选择。回到(1,4),(2,1)情况。如果加入(3,5),就有3种选择。放在(1,4)后面是贪心选择。首先它不差于另起炉灶(与上述证明类似),而且如果放在(2,1)后面达到最优,(1,4)xxx,(2,1)(3,5)yyyy,那么可以做到(1,4)(3,5)yyy,(2,1)(xxxx)。所以(1,4)是贪心选择。至此,我们的每一步要么是贪心选择,要么是唯一的选择。所以算法正确。

 

实现的时候,我们只要存队尾元素的y即可。注意不能忘了在x相同时对y排序。

 

发现做贪心题时感觉很重要,看来还是要多做题呵呵~~

 

源代码:

#include<iostream>
using namespace std;
struct node{
 int x;
 int y;
}s[5001];

#include<iostream>
using namespace std;
int partition(node *a,int p,int q)
{
 int i=p;
 int j=p+1;
 while(j<=q)
 {
  if(a[j].x<a[p].x)
  {
  i++;
  node k=a[i];
  a[i]=a[j];
  a[j]=k;
  }
  j++;
 }
 node k=a[p];
 a[p]=a[i];
 a[i]=k;
 return i;

}
void quicksort(node*a,int p,int q)
{
 if(p<q)
 {
  int r=partition(a,p,q);
  quicksort(a,p,r-1);
  quicksort(a,r+1,q);
 }

}

void sort(int p,int q) {
 int i,j;
 for(i=p;i<q;i++) {
  int min=s[i].y;
  int minmark=i;
  for(j=i+1;j<=q;j++) {
   if(s[j].y<min) {min=s[j].y;minmark=j;}
  }
  node temp;
  temp=s[i];
  s[i]=s[minmark];
  s[minmark]=temp;
 }
}

int findmin(int n) {
 int set[5001];
 int i,sum=1;
 for(i=0;i<5001;i++)
  set[i]=0;
 set[0]=s[0].y;   //set存放队列,并且只需存队尾元素的y坐标
 for(i=1;i<n;i++) {
  int tailmax=0;
  int maxmark=-1;
  int p=0;
  while(set[p]!=0) {
   if(set[p]<=s[i].y) {
    if(set[p]>tailmax) {
     tailmax=set[p];
     maxmark=p;
    }
   }
   p++;
  }
  if(maxmark==-1) {set[p]=s[i].y;sum++;}
  else set[maxmark]=s[i].y;
 }
 return sum;
}

int main()
{
 int num;
 int i,j;
 cin>>num;
 for(i=0;i<num;i++) {
  int n;
  cin>>n;
  for(j=0;j<n;j++)
  cin>>s[j].x>>s[j].y;
  quicksort(s,0,n-1); //先用快排对x排序
  int p=0,q;
  while(p<=n-2) { //在x相同时要对y排序
   if(s[p].x!=s[p+1].x){p++;continue;}
   q=p+1;
   while(q<=n-2) {
    if(s[q].x!=s[q+1].x) break;
    q++; 
   }
   sort(p,q);
   p=q+1;
  }
  cout<<findmin(n)<<endl;
 }
 return 0;
}

原创粉丝点击