贪心

http://acm.hdu.edu.cn/showproblem.php?pid=1050


走廊搬桌子,问共要搬多少次
(这题是会场安排题:  用尽量少的天数安排全部会议,既可以按结束时间排序,也可以按开始时间排序;若是 在一天内尽可能安排最会议这类的题目,则只能按结束时间排序, 今年暑假不AC 就是这类的题目)

两种方法,第二种方法是第一种的简化

只要是贪心方法开数组计数方法解决的的,都能用第二种方法优化,比如这题,再比如http://acm.hdu.edu.cn/showproblem.php?pid=1800这题

方法一

#pragma warning (disable:4786)  
#include<iostream>
#include<algorithm>
using namespace std;
int nMoves[202];      //该数组的size表示需搬的次数
//从房间 s 搬到房间 t
struct Move{
    int s;            
    int t;
};
Move m[202];         
bool cmp ( Move m1, Move m2 ){
	return m1.t < m2.t;       // m1.s < m2.s 也可以,即可以按起点排序,也可以按终点排序
}
int main(){
    int t,n,i,j,k,num,max,h;
    scanf("%d",&t);
	while(t--){
		memset( nMoves, 0, sizeof( nMoves ) );
		scanf("%d",&n);
        for( i = 0; i < n; i ++ )
		{
			//输入各次搬运的起点与终点,起点房间号可能大于终点房间号,故需预处理
			int a,b;
			scanf("%d%d",&a,&b);
			a = ( a + 1 ) / 2;         //对房间号做处理(比如令房间号=(房间号 + 1)/2),使得对门的两个房间的编号相同
			b = ( b + 1 ) / 2;
			if( a < b ){
				m[i].s = a;
				m[i].t = b;
			}
			else {
				m[i].s = b;
				m[i].t = a;
			}
		}       
		//对搬运按终点升序排列
		sort( m, m + n, cmp );
		num = 1;
		nMoves[1] = m[0].t;
		for( i = 1; i < n; i ++ ){
			max = 0;
			k = -1;
			//查找以前搬运次数中搬运终点小于这次的搬运起点,若无符合要求者,则总的搬运次数 +1
			for( j = 1; j <= num; j ++ ){
				if( nMoves[j] < m[i].s && nMoves[j] > max ){
					max = nMoves[j];
					k = j;
				}
			}
			if( k != -1)
				nMoves[k] = m[i].t;
			else {
				num ++;
				nMoves[num] = m[i].t;
			}
		}
		//一次搬运需10分钟,故总时间为搬运总次数num * 10
		printf("%d\n",num * 10);
	}
}
方法二

假设方法一中开的数组的size是每个房间前面的走廊重复出现数的最大值max,如果接下来的搬运在max个数组项中都找不到存放的位置,那就表示一定有一个房间前的走廊重复了 >num 次,矛盾。因此开的数组的size一定 <=num ,而开的数组的size又一定 >=num,综上所述 开的数组的size一定  = num ,即所求答案

#include<iostream>
using namespace std;
int main()
{  
	int M;
    cin>>M;
	while(M--)
    {
	   int i,n,k,l;              //l个需要搬动的桌子,起始n,中止k
	   cin>>l;
       int id[201]={0};
	   while(l--)
	   {
		   cin>>n>>k;
		   if(n>k)
		   {i=n;n=k;k=i;}             //交换小值n在前
		   
           for(i=(n+1)/2;i<=(k+1)/2;i++)            //奇数偶数全加一然后除以2就是走廊号。
			   id[i]++;		               
	   }       
       int max=0;
	   for(i=0;i<201;i++){
           if(max<id[i])
			  max=id[i];        //找房间前的走廊重复出现次数的最大值
	   }
	   cout<<max*10<<endl;  
   }
   
return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值