如题,作为一个计算机专业的大一新生,开学前还是对电脑一窍不通的的小白,在学习了近一个学期的程序设计基础后,别的不敢说,至少打字的速度是呈几何倍增的。邻近期末,想着刷刷学校网站的题目,好家伙,迎头就来了一个会场安排的经典问题。解决这题,真是为难我这平庸的脑瓜了。
好吧,初看这题,毫无头绪,想了十分钟后,大致明白了。先解决输入的问题,一开始想要一个一个输入,不过稍微细想就觉得自己太傻,直接输入怎么保存数据的位置,然后就自然而然地用数组来输入会场时间(用一维还是二维我还考虑了下,后来觉得二维可能比一维更难处理,就放弃了二维)。
第二个要解决的点,想要会场能安排的活动最多,就必须满足1.每次能挑选的活动中(即下一个活动的开始时间大于上一个活动的结束时间),2.选结束时间最小的活动,满足这两个条件,就能保证后面安排更多的活动。(这就是我一开始的想法,其实是有点瑕疵的,所以我后来写代码的时候就吃了个大亏(;´༎ຶД༎ຶ`) )
开始解决问题,首先,第一个活动的安排是挺重要的,不过他的限制条件只有一条,那就是结束时间最小的活动(因为所有的活动都有可能成为第一次活动,所以第一个条件可以忽略,故只考虑第二个条件)
min_idex=1,min=a[1];//活动结束时间存储在a[1],a[3] ...开始时间存储在a[0],a[2]...
for(i=min_idex;i<n;i=i+2)//找出符合条件的首活动
{
if(min>=a[i])
{
min=a[i];
min_idex=i;
}
}
将第一个活动选出来之后,就开始选下一个活动,下一个活动不比首个活动的特殊,他必须满足1,2两个条件。此时,开始思考,找出下一个活动后,我们是否就会开始进行重复的过程?即再找出符合1,2条件的下一个活动,一直找,一直找,直至找不出符合1,2条件的活动为止。
int arrange(int a[],int n)
{
int i,k=0,min=a[1],min_idex=1,flag=1,j=1;
while(flag==1)//flag用来标记是否能找到下一个符合条件的活动
{ flag=0;//flag等于1时符合条件继续找出下一个活动,等于零时即循环结束,再找不到符合条件的活动。
k=0;
for(i=min_idex;i<n;i=i+2)
{
if(min>=a[i])
{
min=a[i];
min_idex=i;
}
}//找出首个活动(同时意味着满足第二个条件)
for(i=min_idex+1;i<n;i=i+2)//
{
if(a[i]>min)//能进入该if的数据代表符合第一个条件,即开始时间大于上一个活动的结束时间
{
flag=1;
a[k++]=a[i];
a[k++]=a[i+1];//!!将找到符合条件1的数据放到数组a中去
}
}//
min_idex=1;
min=a[1];
n=k;//这三行就将下一次的准备工作做好了,接下来我来解释下这三行
if(flag==1) j++;如果符合条件,能安排的活动数量加一
}
return j;
}
其实找出第一个活动是,就意味着,我们将条件2的判断条件写出来了(应该能理解),然后我们想找下一个活动时,其实只要写出条件1的判断就好啦(我们想一下,找下一个活动满足条件1后,是不是可以直接掉头回去用判断首活动写出的条件2代码,来判断这个活动是否满足两个条件)
至于这三行代码,我们不是将符合条件的活动全都存到数组a中去了吗,但是要用这个数组我们还要进行初始化的准备工作,来让循环进行。其中:n=k,就将数组a的长度缩小至我们保存的符合条件1的所有活动了,其他两行作用和开始的min,min_idex作用一样。
到此为止,基本思路都差不多了,所以我先直接把通过oj的代码贴出来,再来说出我的辛酸经历。。
#include<stdio.h>
int arrange(int a[],int n);
void sort(int a[],int n);
int main()
{
int i,g,m,n,a[20000];
scanf("%d",&m);
for(g=0;g<m;g++)
{
scanf("%d",&n);
for(i=0;i<2*n;i++)
scanf("%d",&a[i]);
sort(a,2*n);
printf("%d\n",arrange(a,2*n));
}
return 0;
}
void sort(int a[],int n)
{
int i,j,k;
for(i=0;i<n-2;i=i+2)
{
for(j=0;j<n-2-i;j=j+2)
{
if(a[j]>a[j+2])
{
k=a[j];
a[j]=a[j+2];
a[j+2]=k;
k=a[j+1];
a[j+1]=a[j+3];
a[j+3]=k;
}
}
}
}
int arrange(int a[],int n)
{
int i,k=0,min=a[1],min_idex=1,flag=1,j=1;
while(flag==1)
{ flag=0;
k=0;
for(i=min_idex;i<n;i=i+2)
{
if(min>=a[i])
{
min=a[i];
min_idex=i;
}
}
for(i=min_idex+1;i<n;i=i+2)
{
if(a[i]>min)
{
flag=1;
a[k++]=a[i];
a[k++]=a[i+1];
}
}
min_idex=1;
min=a[1];
n=k;
if(flag==1) j++;
}
return j;
}
/*
1 10
1 2
4 7
6 9
9 11
12 19
13 18
14 19
13 40
2 5
3 6
*/
结果是 4
. 是不是感觉多了很多行。。。没错,这就是我前面说的有点小瑕疵的原因。。我他m以为oj里的测试数据是有序的,就是下一个活动的开始时间比上一个大,但没想到oj的测试数据是无序的。代码写完,我当时是真的不知道哪里错了,修修改改了一个小时都找不到哪里错了,最后想到是不是排序的问题后,又因为脑子昏了排序写错了,又改了半个小时才出来。。。。我真的无语子。。
还有,写这题的上一个礼拜,我们学了递归,所以中途我想,哎哟,这题直接把两个判断条件写出来然后递归一手不久o了?
但我又他喵的没想到,oj的测试数据居然故意除了一组防止用递归的数据,来来的,写完之后时间直接超限。。
这是代码(不要问为什么没有排序,当时还没考虑到乱序(;´༎ຶД༎ຶ`) )
#include<stdio.h>
int arrange(int a[],int n);
int main()
{
int i,g,m,n,a[100];
scanf("%d",&m);
for(g=0;g<m;g++)
{
scanf("%d",&n);
for(i=0;i<2*n;i++)
scanf("%d",&a[i]);
printf("%d",arrange(a,2*n));
}
return 0;
}
int arrange(int a[],int n)
{
int i,k=0,b[100],min=a[1],min_idex=1,flag=0;
for(i=1;i<n;i=i+2)
{
if(min>a[i])
{
min=a[i];
min_idex=i;
}
}
for(i=0;i<n;i=i+2)
{
if(a[i]>=min)
{
flag=1;
b[k++]=a[i];
b[k++]=a[i+1];
}
}
if(flag==1) return arrange(b,k)+1;
return 1;
}
写这个题目太糟心啦,明天还要考四级,莱莱滴!!!!!!
当然啦,写这个题目我还是学会了很多的,至少我知道了这个会场安排是贪心算法的经典例题,哈哈哈。