庆祝下自己完全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;
}
- 庆祝下自己完全AC的第一道贪心~~~
- 自己庆祝自己的BLOG第一天!!
- 博客开通第一天,自己庆祝下。
- POJ3691 - AC自动机的第一道DP
- poj2777 第一道真正意义上完全自己做出来的线段树
- 第一天开始自己的BLOG生涯,庆祝一下
- pku 2524 第一道靠自己ac的并查集
- POJ 2387 第一道Dijkstra AC的很纠结
- poj1990--我的第一道AC树状数组题
- AC的第一道省赛题目代码
- 纪念自己的第一道后缀数组
- 庆祝自己的Blog开通
- 庆祝自己的Blog开张
- 庆祝自己的 BLOG 开通!
- 庆祝自己的博客开通
- 庆祝自己的网站上线
- HDU 2222 AC_Automation 第一道AC自动机
- 自己庆祝自己的blog开通
- java RMI简介和例子
- Linux下PPP拨号上网设置
- java面试题
- shell脚本学习-1.5(小例子)
- 项目经理如何拍好一部电影?
- 庆祝下自己完全AC的第一道贪心~~~
- 海量数据处理:找出现次数最多的那些...
- 我曾用过的杀毒软件
- 44B0下ucos-ii的移植
- 细小的问题---arm-linux-gcc与arm-elf-gcc的区别
- ECLIPSE快捷键大全
- Relocate the service.
- 脑力时代了我们拼的是体力!
- the Secret DAILY TEACHINGS-Day 18