贪心算法
贪心算法
贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择。也就是说,不从整体最优上加以考虑,做出的只是在某种意义上的局部最优解 [1] 。-------------------------------------------百度百科利用贪心法求解的问题应具备如下2个特征1、贪心选择性质一个问题的整体最优解可通过一系列局部的最优解的选择达到,并且每次的选择可以依赖以前作出的选择,但不依赖于后面要作出的选择。这就是贪心选择性质。对于一个具体问题,要确定它是否具有贪心选择性质,必须证明每一步所作的贪心选择最终导致问题的整体最优解2、最优子结构性质
直接来一道例题
P1223 排队接水
题目描述
有 n 个人在一个水龙头前排队接水,假如每个人接水的时间为 T,请编程找出这 n 个人排队的一种顺序,使得 nn 个人的平均等待时间最小。
输入格式
第一行为一个整数 n。
第二行 n 个整数,第 i 个整数 Ti 表示第 i 个人的等待时间 Ti。
输出格式
输出文件有两行,第一行为一种平均时间最短的排队顺序;第二行为这种排列方案下的平均等待时间(输出结果精确到小数点后两位)。
输入输出样例
输入 #11056 12 1 99 1000 234 33 55 99 812输出 #13 2 7 8 1 4 9 6 10 5291.90说明/提示
n≤1000,ti≤106,不保证 t_iti 不重复。
当 t_iti 重复时,按照输入顺序即可(sort 是可以的) 来自洛谷
要想使等待时间最短,就应该让时间短的人先接,这是小学的算术题,我们直接上代码。
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 using namespace std; 5 struct kd{ 6 long long h,t; //声明一个结构体 7 }; 8 kd a[10000]; 9 bool cmp(kd x,kd y) 10 { 11 return x.t<y.t; // 声明排序函数 12 } 13 int main() 14 { 15 int n; 16 double s,c=0; 17 cin>>n; 18 for(int i=1;i<=n;i++) 19 { 20 cin>>a[i].t; 21 a[i].h=i; 22 } 23 sort(a+1,a+1+n,cmp); //排序 24 for(int i=1;i<=n;i++) 25 { 26 cout<<a[i].h<<" "; //输出提水的编号 27 s+=c; //总时间=这个人等待的时间+前面人等待的总时间; 28 c+=a[i].t; //下一个人等待的时间= 这个人等待的时间+这 29 //个人接水的时间 30 } 31 cout<<endl; 32 s/=n; 33 printf("%.2lf",s); 34 }
需要注意一点,等待时间是不包括自己接水的时间的。鬼知道这段时间跑哪去了
一开始写了五六遍代码,样例输出一直是532.00,心态直接崩了。
再来一道
P1803 凌乱的yyy / 线段覆盖
题目背景
快 noip 了,yyy 很紧张!
题目描述
现在各大 oj 上有 nn 个比赛,每个比赛的开始、结束的时间点是知道的。
yyy 认为,参加越多的比赛,noip 就能考的越好(假的)。
所以,他想知道他最多能参加几个比赛。
由于 yyy 是蒟蒻,如果要参加一个比赛必须善始善终,而且不能同时参加 22 个及以上的比赛。
输入格式
第一行是一个整数 nn ,接下来 nn 行每行是 22 个整数 a_{i},b_{i}ai,bi ( a_{i}<b_{i}ai<bi ),表示比赛开始、结束的时间。
输出格式
一个整数最多参加的比赛数目。
输入输出样例
输入 #1
3 0 2 2 4 1 3
输出 #1
2
一开始拿到题,感到无从下手。
仔细想一想,既然不考虑比赛长短,那是不是结束时间越早越好呢?
这是显然的,在不与上一次会议冲突的情况下,当然是结束时间越早越好。
这样,与下一次比赛就可以尽可能的减少冲突。也就是说,下一次可以选择的比赛更多
既然弄清楚了,那我们直接看代码。
#include<iostream> #include<algorithm> using namespace std; struct meet{ long long start,end; }; meet a[1000000]; bool cmp(meet x,meet y) { return x.end<y.end; //声明排序函数,按照结束时间由小到大 } int main() { int n,s=1; cin>>n; for(int i=1;i<=n;i++) cin>>a[i].start>>a[i].end; sort(a+1,a+1+n,cmp); //排序 int m=a[1].end,j=2; //先参加结束最早的 ,结束时间为m while(j<=n) //在总比赛数内进行,按照结束时间早晚循环 { if(a[j].start<m) //如果冲突,看下一场比赛 j++; else{ m=a[j].end; //如果不冲突,总数+1,结束时间更新 j++; s++; } } cout<<s; return 0; }