题目网址:http://wikioi.com/problem/1385/
昨天由于家里有点事情,就没有继续忙了。其实昨天上午已经按照我自己的思路把代码写出来了。可惜结果总有两个不能ac了。
后来参考了相关思路,发现自己思考问题的时候,太过拘谨。不过也可以理解,因为我本身对排序算法就不是很熟悉,总觉得像快速排序里面有递归调用就会很慢。
其实不是这样。后来写出的算法,明显比自己之前想象的算法要快一倍,而且思路清晰,容易调试。
果然,到了真正比赛的时候,还是写思路清晰的算法比较好。一是好调试错误。二是未必会慢。
这个是我自己设想的算法,一个是实现起来繁琐。情况复杂。前后融合都要考虑,二是,写到后面发现,还是要借助排序。因为再不排序,又会复杂,成指数级= =。
/*
300---------1000
700-------1200
1500---------2100
2000 2700
1、第一个组合与所有匹配,能融合,就融合,并标记融合过的;
2、产生的新组合与剩下的未标记的融合,同上;
3、该组合不能再融合时,从下一个未标记的开始搜索融合;
4、下一个标记的不能融合时候,再下一个;
5、所有都标记上了,结束。选出最长时间与最短时间
*/
#include <stdio.h>
#include <stdlib.h>
typedef struct _NODE
{
int beg;
int end;
}NODE;
//0,右边融合;1,左边融合;2,中间,不用理会;-1,不相交
int check(NODE i1,NODE i2)
{
if( i2.beg >= i1.beg && i2.beg <= i1.end && i2.end > i1.end )
return 0;
else if( i2.end >= i1.beg && i2.end <= i1.end && i2.beg < i1.beg )
return 1;
else if( i2.beg >= i1.beg&& i2.end<= i1.end)
return 2;
else
return -1;
}
void quick_sort(NODE *node,int l,int r)
{
if (l < r)
{
//Swap(s[l], s[(l + r) / 2]); //将中间的这个数和第一个数交换 参见注1
int i = l, j = r;
NODE x = node[l];
while (i < j)
{
while(i < j && node[j].beg >= x.beg) // 从右向左找第一个小于x的数
j--;
if(i < j)
node[i++] = node[j];
while(i < j && node[i].beg < x.beg) // 从左向右找第一个大于等于x的数
i++;
if(i < j)
node[j--] = node[i];
}
node[i] = x;
quick_sort(node, l, i - 1); // 递归调用
quick_sort(node, i + 1, r);
}
}
int main()
{
int n;
scanf("%d",&n);
int i;
NODE *input = (NODE *)malloc(sizeof(NODE) * n);
int *flag = (int *)malloc(sizeof(int) * n);
for(i=0 ; i< n; i++)
{
//0 未标记 ;1已经融合过; 2加工过
flag[i] = 0;
scanf("%d %d",&input[i].beg,&input[i].end);
}
flag[0] = 2;
int isAdd = 0;
int j=0;
int status;
int cou=1;
while(1)
{
for( i=j+1 ; i< n ; i++)
{
if( flag[i]==0)
{
status = check(input[j],input[i]);
if( status==0)
{
input[j].end= input[i].end;
isAdd = 1;
flag[i]=1;
}
else if( status==1)
{
input[j].beg= input[i].beg;
isAdd = 1;
flag[i]=1;
}
else if(status==2 )
{
flag[i]=1;
}
}
}
//当融合到无法融合的时候,寻找下一个
if( isAdd == 0)
{
for(i=j ; i < n && flag[i]!=0; i++);
//全被标记,结束寻找
if( i==n)
{
break;
}
j = i;
flag[j] = 2;
cou++;
}
isAdd = 0;
}
int max_ji = 0,max_meiji = 0;
NODE *getMax = (NODE *)malloc(sizeof(NODE) * cou);
//筛选出最终的时间组合,并找出最大挤奶时间
for(i=0,j=0 ; i < n; i++)
{
if(flag[i] ==2)
{
getMax[j++] = input[i];
max_ji = (input[i].end-input[i].beg) > max_ji ? (input[i].end-input[i].beg) : max_ji;
}
}
//排序先
quick_sort(getMax,0, cou-1);
//筛选最大不挤奶时间
for(i=0 ; i< cou-1 ; i++)
{
max_meiji = (getMax[i+1].beg- getMax[i].end)>max_meiji ?(getMax[i+1].beg- getMax[i].end):max_meiji;
}
printf("%d %d",max_ji,max_meiji);
return 0;
}
这个是后来根据参考,自己纠正的算法,首先把排序做了。用快排,然后思路就瞬间清晰了。
其实,本训练的目的,就是掌握不同问题的解决思路,在每个问题解决的时候,学会使用其中应当明白的算法。
自然,解法还是有很多的。但是要以题目本身的目的来围绕着学习。
像本类题目的目的,就是写出容易理解的枚举算法。或者通过一定的优化手段,再来枚举。之前一直没想通这个怎么优化。原来就是利用我一直不熟悉的排序算法。
看来之后还要好好补补排序算法了。先把快排弄好吓,快速理解。
#include <stdio.h>
#include <stdlib.h>
typedef struct _NODE
{
int beg;
int end;
}NODE;
void quick_sort(NODE *node,int l,int r)
{
if (l < r)
{
//Swap(s[l], s[(l + r) / 2]); //将中间的这个数和第一个数交换 参见注1
int i = l, j = r;
NODE x = node[l];
while (i < j)
{
while(i < j && node[j].beg >= x.beg) // 从右向左找第一个小于x的数
j--;
if(i < j)
node[i++] = node[j];
while(i < j && node[i].beg < x.beg) // 从左向右找第一个大于等于x的数
i++;
if(i < j)
node[j--] = node[i];
}
node[i] = x;
quick_sort(node, l, i - 1); // 递归调用
quick_sort(node, i + 1, r);
}
}
int main()
{
int n;
scanf("%d",&n);
NODE *input = (NODE *)malloc(sizeof(NODE) *n);
int i;
for(i=0 ; i < n; i++)
{
scanf("%d %d",&input[i].beg,&input[i].end);
}
//通过排序的方法,就解决了情况复杂多变的情况。
//本题的核心,就是用排序的方法,简化线段离散化的情况,
//使得问题分析变得简单。
quick_sort(input,0,n-1);
int max_continus=0,max_idle=0;
int max_beg= input[0].beg,max_end = input[0].end;
for(i=1 ; i< n ; i++)
{
//下一个线段的beg在前一个线段内部,下一个线段将被吸收,取两者最大的end
if( input[i].beg <= max_end)
{
max_end = input[i].end>max_end ? input[i].end:max_end;
}
//反之,将开始另外一段线段的比较。
else
{
max_continus = (max_end-max_beg)>max_continus ? (max_end-max_beg):max_continus;
max_idle = (input[i].beg - max_end)> max_idle ?(input[i].beg - max_end): max_idle;
max_beg = input[i].beg;
max_end = input[i].end;
}
}
//竟然忽略了最后要把结果再次比较一下。嘿哈。浪费了我20分钟。
max_continus = (max_end-max_beg)>max_continus ? (max_end-max_beg):max_continus;
max_idle = (input[i].beg - max_end)> max_idle ?(input[i].beg - max_end): max_idle;
printf("%d %d",max_continus,max_idle);
return 0;
}