算法设计与分析(三) 贪心法

时间:2025-03-31 07:10:12

贪心法的思路很简单,只需要对比最近的就行,注意有时候需要调整次序
我已经被调整的找不着北了)
T1
题目内容:
有n头牛(1<=n<=50,000)要挤奶。给定每头牛挤奶的时间区间[A,B]
注:1<=A<=B<=1,000,000,A,B为整数
牛需要呆在畜栏里才能挤奶。一个畜栏同一时间只能容纳一头牛。问至少需要多少个畜栏,才能完成全部挤奶工作,以及每头牛都放哪个畜栏里?注意:在同一个畜栏的两头牛,它们挤奶时间区间不能在端点重合。

#include<>
#include<>
int count=1;
void Solve(int start[],int end[],int flag[],int n) {
int i, j, t, k = 0;
int p,q;
int a,b;
int stak[1000] = { 0 };
for (i = 0;i < n;i++)
stak[i] = i;
for (i = 0;i < n - 1;i++) {
k=stak[i];
t=start[k];
for (j=i+1;j<n;j++) {
t=start[stak[i]];
p=stak[j];
if (t>start[p]){
q=stak[i];
stak[i] = stak[j];
stak[j] = q;
}
}
}//按开始时间递增排序,序号为stak里包含的下标
flag[0]=count;
for(i=0;i<n-1;i++){
if(flag[stak[i]]==0)
flag[stak[i]]=++count;
for(j=i+1;j<n;j++){
if(end[stak[i]]<start[stak[j]]){
flag[stak[i]]=flag[stak[j]]=count;
end[stak[i]]=end[stak[j]];
}
}

}
printf("%d\n",count);
for(i=0;i<n;i++){
printf("%d\n",flag[i]);
}
}
int main(){
int n,i,j;
int start[1000]={0};
int end[1000]={0};
int flag[1000]={0};
scanf("%d",&n);
for(i=0;i<n;i++){
scanf("%d %d",&start[i],&end[i]);
}
Solve(start,end,flag,n);
system(“pause”);
return 0;
}
这题的思路不难,就是按照开始时间按排序,递增,依次遍历看前一个的结束时间和后面元素的开始时间,如果前者小于后者那么把它们放进一个栏,就是后者的count等于前者(在新的循环开始前检查前者的栏杆标记,不是0表明这头牛已经被放进某个栏,是0就新建一个栏,count++),不是的话再往后推,这里注意要调整这个栏的结束时间,更新一下就行,像题目那个次序有个问题就是两者之间的空隙可能还能继续放牛,所以要排序,排完序就是下面的问题。
有个问题就是题目输出的次序不是按照排序后的次序,所以在排序的时候新建一个数组存储排序之后它的数组下标,但是原数组顺序不变,这样在最后输出对应栏杆标号的时候才能和题目对上,新的问题是这么做在循环检查是否符合条件时会很晕,我也不知道这么简单一个题目我是怎么把自己绕晕的
T2
题目内容:
设x1,x2,… ,xn是实直线上的n个点。用固定长度的闭区间覆盖这n个点,至少需要多少个这样的固定长度闭区间?设计求解此问题的有效算法。对于给定的实直线上的n个点和闭区间的长度k,编程计算覆盖点集的最少区间数。

#include<>
#include<>
int count=1;
void Solve(int x[],int n,int length) {
int i,j,k;
int t;
for(i=0;i<n-1;i++)
for(j=i+1;j<n;j++)
if(x[i]>x[j]){
t=x[i];
x[i]=x[j];
x[j]=t;
}//递增排序
t=x[0];
for(i=1;i<n;i++){
k=x[i]-t;
if(k>length){
count++;
t=x[i];
}
}
printf("%d",count);
}
int main(){
int n,i;
int length;
int x[100]={0};
scanf("%d%d",&n,&length);
for(i=0;i<n;i++)
scanf("%d",&x[i]);
Solve(x,n,length);
system(“pause”);
return 0;
}
这题只需要排序,设置最左点为起始点,设置它的区间为1(既是标号也是计数),向后推点,间距小于length那么继续向后,一旦超过就用新的点作为起始点,同时区间更新即可。

贪心法相对简单一些,排好序(或者按一定次序)推过去就可以了,就是求目前最小情况下的最优解。