A:
给定一串字母,每次从该字母串的头或尾取一个字母加入到新串中,要求所得新串字典序最小
思路:
显然,每次直接比较头部和尾部字母就好,头尾的指针在取字母的时候更新。
考虑首尾字母相同的情况,此时需要比较第二个和倒数第二个字母,如果仍相同,则继续比较下一个,所以有
for(int i=0;i+a<=b;i++){
if(p[a+i]<p[b-i])
只要两字母不再相同就可以break跳出,取字母
#include<stdio.h>
int p[2010];
int q[2010];
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++) {
scanf(" %c",&p[i]);
}
int a=1,b=n;
int pos=0;
while(a<=b){
bool left=false;
for(int i=0;i+a<=b;i++){
if(p[a+i]<p[b-i]){
left = true;
break;
}
//下面这个else if如果删去会出错
else if(p[a+i]>p[b-i]){
left = false;
break;
}
}
if(left) q[++pos]=p[a++];
else q[++pos]=p[b--];
}
int ans=0;
for(int i=1;i<=n;i++){
printf("%c",q[i]);
ans++;
if(ans==80){
printf("\n");
ans=0;
}
}
return 0;
}
B:
有N个点,其中一些点插眼,眼的作用距离为R。如,插在点x=11上的距离为10的眼,最远可以作用到x=1与x=21的点。
求能使所有点被监视的最少插眼数目
又读错题了orz,以为是在数轴上任意地方插眼,原来是必须在点上插眼orz
#include<stdio.h>
#include<algorithm>
using namespace std;
int main()
{
int a[1006];
int r,n;
while(scanf("%d%d",&r,&n)==2){
if(r==-1&&n==-1) break;
for(int j=1;j<=n;j++) scanf("%d",&a[j]);
sort(a+1,a+n+1);
int ans=0,i=1;
while(i<=n){
int s=a[i];//以未被监视的点中最左边的那一个作为起点
while(i<=n&&a[i]<=s+r) i++;//一直前进,直到当前点超出了监视距离
int p=a[i-1];
ans++;//给前一个点打标记,这样才能监视到起点
while(i<=n&&a[i]<=p+r) i++;//从监视点的下一个点继续出发,直到当前点超出了监视距离
}
printf("%d\n",ans);
}
return 0;
}
D:
有T个工作时间段,且有N头给定工作时间的牛,要求:雇佣尽量少的牛使得1-T时间段内都至少有一头牛工作。求这个最小数量。
贪心算法是:将所有牛按起始时间从早到晚排序,每次都挑可接班的牛中结束时间最晚的。
(这个怎么证啊啊啊啊啊啊啊)
有个坑:1-4,5-10也是连续的从1到10时间段的选择,不一定要1-4,4-10.
#include<stdio.h>
#include<algorithm>
using namespace std;
struct str_cow{
int begin;
int end;
}cow[25005];
bool cmp(str_cow a,str_cow b){
if(a.begin==b.begin) return a.end<b.end;
else return a.begin<b.begin;
}
int main()
{
int n,t;
scanf("%d%d",&n,&t);
for(int i=1;i<=n;i++) scanf("%d%d",&cow[i].begin,&cow[i].end);
sort(cow+1,cow+n+1,cmp);
//排序,最先开始的排在前面,如果同一时间开始,则结束最早的排在前面
int tail1=-1;
for(int i=1;i<=n;i++){
if(cow[i].begin!=1) break;
if(cow[i].end>tail1) tail1=cow[i].end;
}
//牛的最晚接班时间
int ans=1;
//雇佣牛的数目
int tail2=-1;
int ok=1;
while(tail1<t&&ok==1){//只要当前选好的结束时间还没达到要求的结束时间,就继续选下一头牛
ok=0;//先假设这里开始接不上
for(int i=1;i<=n;i++){
if (cow[i].begin>tail1+1) break;
//如果第i头牛的开始时间比接班时间要晚,接不上,后面的也接不上
//在所有开始时间小于当前接班时间的牛中找结束时间最晚的那一个
else if(cow[i].end>tail2) {
ok=1;
tail2=cow[i].end;
//否则,记下第i头牛的结束时间,如果结束时间要更晚,就选用
}
}
tail1=tail2;
ans++;//选用数+1
}
if(ok==0) printf("-1");
else printf("%d",ans);
return 0;
}
E:
给定一些点的坐标(保证y>0)及圆的半径,为保证这些点能被若干个圆心在x轴上的圆全部覆盖,求需要圆的最少数目。如果不能全部覆盖,输出-1
思路1(也许是错的,因为A不掉,原因未知):
将点按照x坐标从小到大排序。每次考虑第一个未被雷达覆盖到的点,用d²-y²得出恰好覆盖该点的圆的圆心所在。然后向右遍历各点,计算与该圆心的距离以确认是否被覆盖,若出现没有覆盖的点,重复上述步骤,直到已经计算过最后一个点。
思路2:
假设雷达就放在岛上,则当岛可以在原来情况被覆盖时,雷达的范围应与x轴有交点,将交点作为这个岛的左右边界。显然,当岛与岛之间左右边界有重叠部分时,两岛可以共用一个雷达。
错误分析:
从昨天写到现在,就差照着题解码了……
问题一:边界排序
毫无疑问是将右边界从小到大排,但是没有考虑到右边界相等时的情况。
右边界相等时,应将左边界从大到小排,确保区间大的在前面。
问题二:数据类型
一开始d写成了int
最大右边界变量right一开始也是int,A得过才有鬼咯
问题三:雷达初始值问题
这里雷达初始值应为1,既可以保证n=1时有1个雷达,又符合n>1时的情况
#include<stdio.h>
#include<algorithm>
#include<math.h>
using namespace std;
struct str_island{
float x;
float y;
float round_l;
float round_r;
}island[1005];
bool cmp(str_island a,str_island b){
if(a.round_r==b.round_r) return a.round_l>b.round_l;
return a.round_r<b.round_r;
}
int main()
{
int kase=0;
float d;
//类型啊!!一开始是int
int n;
while(scanf("%d%f",&n,&d)==2&&n&&d){
int radar=0;
for(int i=1;i<=n;i++) scanf("%f%f",&island[i].x,&island[i].y);
//载入小岛坐标
int ok=1;
for(int i=1;i<=n;i++){
if(d>=island[i].y){
//对于这个小岛,假设雷达在岛上,则范围与x轴应有交点,算出左右端点
island[i].round_l=island[i].x - sqrt(d * d - island[i].y * island[i].y);//左端点
island[i].round_r=island[i].x + sqrt(d * d - island[i].y * island[i].y);//右端点
}
else{
printf("Case %d: -1\n",++kase);
ok=0;
break;
//有一个岛不能被覆盖,直接跳出
}
}
if(ok==0) continue;
else{
radar=1;
//注意雷达的初始数量
//考虑到下面的计算步骤以及只有一个岛的情况
//这里应该一开始就放了一个雷达
sort(island+1,island+n+1,cmp);
//将小岛覆盖区间的右端点从小到大排序
float right=island[1].round_r;
//注意类型,这里一开始写的是int
for(int i=2;i<=n;i++){
if(island[i].round_l>right){
radar++;
//超出了上一个雷达的覆盖范围,
right=island[i].round_r;
//新放了个雷达,故更新边界
}
}
printf("Case %d: %d\n",++kase,radar);
}
}
return 0;
}