1083 -- Moving Tables

烂漫一生 提交于 2020-12-13 10:59:11

 Moving Tables

Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 32929   Accepted: 11032

Description

The famous ACM (Advanced Computer Maker) Company has rented a floor of a building whose shape is in the following figure. 

The floor has 200 rooms each on the north side and south side along the corridor. Recently the Company made a plan to reform its system. The reform includes moving a lot of tables between rooms. Because the corridor is narrow and all the tables are big, only one table can pass through the corridor. Some plan is needed to make the moving efficient. The manager figured out the following plan: Moving a table from a room to another room can be done within 10 minutes. When moving a table from room i to room j, the part of the corridor between the front of room i and the front of room j is used. So, during each 10 minutes, several moving between two rooms not sharing the same part of the corridor will be done simultaneously. To make it clear the manager illustrated the possible cases and impossible cases of simultaneous moving. 

For each room, at most one table will be either moved in or moved out. Now, the manager seeks out a method to minimize the time to move all the tables. Your job is to write a program to solve the manager's problem.

Input

The input consists of T test cases. The number of test cases ) (T is given in the first line of the input file. Each test case begins with a line containing an integer N , 1 <= N <= 200, that represents the number of tables to move. 
Each of the following N lines contains two positive integers s and t, representing that a table is to move from room number s to room number t each room number appears at most once in the N lines). From the 3 + N -rd 
line, the remaining test cases are listed in the same manner as above.

Output

The output should contain the minimum time in minutes to complete the moving, one per line.

Sample Input

3 
4 
10 20 
30 40 
50 60 
70 80 
2 
1 3 
2 200 
3 
10 100 
20 80 
30 50 

Sample Output

10
20
30

Source

 

 题意:

   在一个狭窄的走廊里将桌子从一个房间移动到另一个房间,走廊的宽度只能允许一个桌子通过。给出t,

   表示有t组测试数据。再给出n,表示要移动n个桌子。n下面有n行,每行两个数字,表示将桌子从a房间

   移到b房间。走廊的分布图如一图所示,每移动一个桌子到达目的地房间需要花10分钟,问移动n个桌子

   所需要的时间。

 

思路:

  要在一个走廊搬桌子,从第s号房间到第t号房间,可以多组一起搬,但不能同时。
  搬重合的,例如10-20,30-40可以一起搬,但是10-20,15-30 不能同时搬,求总计用多少时间能搬完桌子(最短时间),
  根据题目中所给的房间号,可以发现房间号是上下排的,也就是说,从1-3,4-5 其实是不能同时搬动的。
  而且,要注意到,偶数和奇数的不同。考虑所有情况的过程也比较复杂……
  可以很简单的考虑到贪心算法,类似于活动安排问题。考虑到活动安排问题是最早结束时间优先
(为了给剩余活动剩余尽可能长的时间)。这道题可以将走廊看成时间轴。
  但是,我还没有证明贪心算法用在这道题上面的正确性。虽然通过了,但是有两种可能1:测试数据有点水 2:算法正确。
  所以算法正确性有待证明。
 1 /*
 2 For each room, at most one table will be either moved in or moved out.
 3 可以用map
 4 */
 5 #include<iostream>
 6 #include<map>
 7 using namespace std;
 8 int main()
 9 {
10     int t;
11     cin>>t;
12     while(t)
13     {
14         int n;
15         cin>>n;
16         map<int,int> table;
17         int a,b;
18         int m = n;
19         while(n)
20         {
21             cin>>a>>b;
22             //if(a%2) a=a+1;
23             //if(b%2) b = b+1;
24             if(b<a)
25             {
26                 a = b+a;b=a-b;a = a-b;
27             }
28             table[a] = b;
29             n--;
30         }
31         /*
32         map<int,int>::iterator print = table.begin();
33         for(;print != table.end();print++)
34             cout<<print->first<<" "<<print->second<<endl;*/
35         map<int,int>::iterator iter = table.begin();
36         for(;iter!=table.end();iter ++)
37         {
38             if(m <= 1) break;
39             map<int,int>::iterator temp = iter;
40             for(;temp!=table.end();)
41             {
42                 if((temp->first >= (iter->second+2) && (iter->second%2)==(temp->first%2) && (iter->first%2)==(iter->second%2) && (iter->second)%2 == 1)//在同侧,可以一起移动
43                    ||(temp->first >= (iter->second+3) && (iter->second%2)!=(temp->first%2) && (iter->first%2)==(iter->second%2) && (iter->second)%2 == 1)//在两侧,可以一起移动
44                    ||(temp->first >= (iter->second+2) && (iter->second%2)==(temp->first%2) && (iter->first%2)==(iter->second%2) && (iter->second)%2 == 0)//在同侧,可以一起移动
45                    ||(temp->first >= (iter->second+1) && (iter->second%2)!=(temp->first%2) && (iter->first%2)==(iter->second%2) && (iter->second)%2 == 0)//在两侧,可以一起移动
46                    ||(temp->first >= (iter->second+2) && (iter->second%2)==(temp->first%2) && (iter->first%2)!=(iter->second%2) && (iter->second)%2 == 0)
47                    ||(temp->first >= (iter->second+1) && (iter->second%2)!=(temp->first%2) && (iter->first%2)!=(iter->second%2) && (iter->second)%2 == 0)
48                    ||(temp->first >= (iter->second+2) && (iter->second%2)==(temp->first%2) && (iter->first%2)!=(iter->second%2) && (iter->second)%2 == 1)
49                    ||(temp->first >= (iter->second+3) && (iter->second%2)!=(temp->first%2) && (iter->first%2)!=(iter->second%2) && (iter->second)%2 == 1)
50                    )
51                 {
52                     //cout<<temp->first<<endl;
53                     iter->second = temp->second;
54                     int y = temp->first;
55                     temp++;
56                     table.erase(y);
57                 }
58                 else{temp++;}
59             }
60         }
61         cout<<table.size()*10<<endl;
62         table.clear();
63         t--;
64     }
65     return 0;
66 }

 

 

另一种解决方法(同样为贪心):

输入的时候只存了一侧的桌子号,也就是说输入的3,我存成4,这样就避免1-3,4-5的问题了,然后贪心方法,
排序,计算,出结果。。。

ACM-贪心之Moving Tables——hdu1050

 1 #include <iostream>
 2 using namespace std;
 3 
 4 struct table{
 5     int front,back;
 6     bool use;
 7 }tb[10001];
 8 
 9 
10 int main()
11 {
12     int T,N,total;            //T为有几组数据,N为每组数据有几行数据,total为总用时
13     int i,j,temp;            
14     table tem;
15 
16     cin>>T;
17     while(T--)
18     {
19         //**************************   输入
20         cin>>N;
21         for(i=0;i<N;++i)
22         {
23             cin>>tb[i].front>>tb[i].back;
24 
25             if(tb[i].front%2==1)
26                 tb[i].front+=1;
27             if(tb[i].back%2==1)
28                 tb[i].back+=1;
29 
30             if(tb[i].front>tb[i].back)
31             {
32                 temp=tb[i].front;
33                 tb[i].front=tb[i].back;
34                 tb[i].back=temp;
35             }
36         
37             tb[i].use=true;
38         }
39         //*************************       排序
40 
41         for(i=0;i<N-1;++i)
42             for(j=i+1;j<N;++j)
43                 if(tb[i].front>tb[j].front)
44                 {
45                     tem=tb[i];
46                     tb[i]=tb[j];
47                     tb[j]=tem;
48                 }
49 
50         //*************************       计算值
51         total=0;
52         for(i=0;i<N;++i)
53         {
54             if(tb[i].use==false)
55                 continue;
56             
57             temp=tb[i].back;
58 
59             for(j=i+1;j<N;++j)
60             {
61                 if(tb[j].use==false)
62                     continue;
63                 if(tb[j].front>temp)
64                 {
65                     tb[j].use=false;
66                     temp=tb[j].back;
67                 }
68             }
69             
70             total+=10;
71         }
72         
73 
74         //*************************     输出
75         cout<<total<<endl;
76         
77 
78     }
79 
80     return 0;
81 }

另一种思路:

  若移动多个桌子时,所需要经过的走廊没有重合处,即可以同时移动。若有一段走廊有m个桌子都

     要经过,一次只能经过一个桌子,则需要m*10的时间移动桌子。设一个数组,下标值即为房间号。

     桌子经过房间时,该房间号为下标对应的数组值即加10。最后找到最大的数组值,即为移动完桌子

     需要的最短时间。

ACM--移动桌子--贪心--HDOJ 1050--Moving Tables

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 int main(){
 6     int t,n,count[410],i,start,end,k;
 7     scanf("%d",&t);
 8     while(t--){
 9         scanf("%d",&n);
10         memset(count,0,sizeof(count));
11         while(n--){
12             scanf("%d%d",&start,&end);
13             //可能出发位置比目的地房间大。
14             if(start>end){
15                 //无论大小,我们都可以看做从小的房间移动到大的房间
16                 k=start;
17                 start=end;
18                 end=k;
19             }
20             if(start%2==0)//考虑实际情况,出发房间为偶数是减一,可参照题中给出的图一
21                start-=1;
22             if(end%2==1)//目的地房间为奇数时加一
23                end+=1;
24             for(i=start;i<=end;++i)
25                count[i]+=10;
26         }
27         printf("%d\n",*max_element(count,count+400));//STL中寻找数列最大值函数
28     }
29     return 0;
30 }

表示这种方法真是神气,get!!

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!