HDU1050Moving Tables(贪心,树状数组两种解法)

问题说明
ACM著名(高级电脑制造商)公司租了地面建筑,其形状如下图所示。 

HDU1050Moving Tables(贪心,树状数组两种解法)_第1张图片

楼有200间客房,每沿着走廊的北侧和南侧。最近公司做了一个计划,以改革其系统。改革包括房间之间的表动了不少。由于楼道狭窄,所有的表都是大的,只有一个表可以通过走廊。有些计划需要使移动高效。经理想通了以下计划:将表从一个房间到另一个房间,可以在10分钟内完成。当从一个房间移动表i到J室,部分前面房间之间的走廊上,我和J室的前面。所以,在此期间,每10分钟,一些移动的同时进行两个房间之间不共享相同的部分的走廊。要清楚经理说明了可能的情况下,不可能的情况下同时移动。

HDU1050Moving Tables(贪心,树状数组两种解法)_第2张图片

每间客房,最多一个表将被移动或移动。现在,经理寻求以最少的时间,将所有表的方法。你的任务是写一个程序,以解决经理人的问题。
 
原题: http://acm.hdu.edu.cn/showproblem.php?pid=1050
题解:此题有两种方法:方法一:由于n太小,可以用一种最简单的解法:即每走一次就对走过的走廊加1,然后遍历一边找出最大的覆盖值;和树状数组有点相似;
方法二:先对起点排序,然后判断这些线段是否可以和其他的线段放在一排,不能放在一排单放在一排,flag值就加1;
注意:1:起点与终点的大小要先比较大小,因为可以有类似这种情况40-——30;
2:奇偶房间对称,共用一个走廊,所以要先对s和e进行奇偶判断,奇数就加一;
代码实现:
方法一:
#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;
}


方法二:
#include<stdio.h>
#include<cstring>
#include<algorithm>
using namespace std;
#pragma comment(linker,"/STACK:102400000,102400000")
#define MAX   205
struct line1
{
     int s,e;
}line[MAX];
int sign[MAX];//为标记可以放在一排的最后的终点位置;
bool cmp(line1 x,line1 y)
{
     return(x.s<y.s);
}//对起点进行排序
int main()
{
   //freopen("input.txt","r",stdin);
   int i,j,t,n,x,y;
   scanf("%d",&t);
   while(t--)
   {
        scanf("%d",&n);
        memset(sign,-1,sizeof(sign));//标记要初始化为-1,因为起点可能是0;
        for(i=0;i<n;i++)
        {
             scanf("%d%d",&x,&y);
             if(x%2)x+=1;//走廊是奇偶房间公用的
             if(y%2)y+=1;
             line[i].s=x>y?y:x;//起点与终点的大小进行比较
             line[i].e=x>y?x:y;
        }
        sort(line,line+n,cmp);//排序
        int flag=0;//标记最大的可以排成多少排
        for( i=0;i<n;i++)
        {
             for(j=0;j<n;j++)
             {
                  if(line[i].s>sign[j])
                  {
                       sign[j]=line[i].e;
                       if(j+1>flag)flag=j+1;
                       break;//一旦遇到这段线段可以放在某一排就跳出循环
                  }
             }
        }
        printf("%d\n",flag*10);
   }
   return 0;
}


你可能感兴趣的:(HDU,贪心)