【备战蓝桥杯】USACO--> Milking Cows[2]

题目网址: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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值