http://acm.hdu.edu.cn/showproblem.php?pid=1050
走廊搬桌子,问共要搬多少次
两种方法,第二种方法是第一种的简化
只要是贪心方法开数组计数方法解决的的,都能用第二种方法优化,比如这题,再比如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;
}