POJ 1508-------Skyscraper Floor

问题描述:

Skyscraper Floors

Time Limit: 10000MS Memory Limit: 10000K

Total Submissions: 810 Accepted: 175

Description

 

What a great idea it is to build skyscrapers! Using not too large area of land, which is very expensive in many cities today, the skyscrapers offer an extremely large utility area for flats or offices. The only disadvantage is that it takes too long to get to the upper floors. Of course these skyscrapers have to be equiped not only with a stairway but also with several elevators. But even using ordinary elevators is very slow. Just imagine you want to get from the very top floor to the base floor and many other people on other floors want the same. As a result the elevator stops on almost every floor and since its capacity is limited and the elevator is already full from the upper floors, most stops are useless and just cause a delay. If there are more elevators in the skyscrapers, this problem is a little bit eliminated but still not completely. Most people just press all the buttons of all the elevators and then take the first one so that all elevators will stop on the floor anyway. 

 

However, the solution exists as we shall see. The Antique Comedians of Midilesia headquarters reside in a skyscraper with a very special elevator system. The elevators do not stop on every floor but only on every X-th floor. Moreover each elevator can go just to a certain floor Y (called starting floor) and cannot go any lower. There is one high-capacity elevator which can stop on every elevator's starting floor. 

 

The ACM has a big problem. The headquarters should be moved to another office this week, possibly on a different floor. Unfortunately, the high-capacity elevator is out of order right now so it is not always possible to go to the base floor. One piece of furniture cannot be moved using the stairway because it is too large to pass through the stairway door. You are to write a program that decides whether it is possible to move a piece of furniture from the original office to the other.

Input

 

The input consists of N cases. The first line contains only one positive integer N. Then follow the cases. Each case starts with a line containing four integers F, E, A, B, where F, 1 <= F < 50000000 determines the number of floors in the skyscraper (this means that there are floors 0 to F-1), E, 0 < E < 100 is the number of elevators and A, B, 0 <= A,B < F are numbers of the two floors between which the piece of furniture should be moved. Then follow E lines. Each of them contains description of one elevator. There are exactly two integers X and Y, X > 0, Y >= 0 at each line. Y determines, that the elevator starts on the Y-th floor and X determines, that it stops on every X-th floor, eg. for X = 3, Y = 7 the elevator stops on floors 7, 10, 13, 16, etc.).

Output

 

For each case, print exactly one line. If floor B is reachable from floor A not using the stairway, print the sentence 'It is possible to move the furniture.', otherwise print 'The furniture cannot be moved.'.

Sample Input

 

2

22 4 0 6

3 2

4 7

13 6

10 0

1000 2 500 777

2 0

2 1

Sample Output

 

It is possible to move the furniture.

The furniture cannot be moved.


这个是我昨天写的,可以改进。我现在比较忙,没时间改了。等我有时间在来改进。先放在这里了。


#include<iostream>
#include<fstream>
#include<cstdlib>
using namespace std;

int N;
long long F,E;
long long A,B;
int X[100];
int Y[100];
int isChosen[100];
int HasCommon[100][100];

ifstream fin("C:\\data40.in");
//这是《算法竞赛入门》里给出了算法,作用是求两条直线的交点,这里的作用是判断两个电梯能否在同一楼层停下,原因是mX[i]+Y[i]=nX[j]+Y[j],变换之后是mX[i]-nX[j]+Y[i]-Y[j]=0,和直线的交点一样,然后把结果储存在HasCommon[][]数组中。详见《入门》179页(其实还能改进的,但我现在还写不出来,如果在改进一下就能把后面的循环都省去了,直接算答案了)。
void gcd(int a,int b,int& d,int& x,int& y)
{
     if(!b)
     {
	     d=a;
	     x=1;
	     y=0;
     }
     else
     {
	     gcd(b,a%b,d,y,x);
	     y=-x*(a/b);
     }
}

//初始化主体算法中要用到的两个判据
void Init()
{
     memset(isChosen,0,sizeof(isChosen));
     memset(HasCommon,0,sizeof(HasCommon));
     for(int i=0;i<E-1;++i)
     {
             for(int j=i+1;j<E;++j)
             {
                     int a,b,d,x,y;
                     a=X[i];
                     b=X[j];
                     gcd(a,b,d,x,y);
                     if(!(x==0&&y==0))
                     {
			     HasCommon[i][j]=1;
			     HasCommon[j][i]=1;
                     }
             }
     }
     for(int i=0;i<E;++i)
     {
             for(int j=0;j<E;++j)
             cout<<HasCommon[i][j]<<"\t";
             cout<<endl;
     }
     system("pause");
}

//这个循环太难想了,我原本以为这个是银币问题的变体,想用循环数组来做,但是用了循环数组就发现可能会一直循环下去,就放弃了。然后我想啊想,就想出了这个循环
int DP(int startpos,int endpos)
{
	for(int i=0;i<E;++i)
	{
		if(isChosen[i]==0)//电梯之前是不能被选过了。至于为什么不能被选过,是这个问题的关键点   (*)
		{
			if(endpos>=Y[i]&&((endpos-Y[i])%X[i]==0))//判断电梯能否到达最后一个楼层,即方程mX[i]+Y[i]=endpos有整数解   (**)
			{
				isChosen[i]=1;//能到达就把这个电梯标注为已经处理过的,然后对其进行处理.这是(*)的后续推理
				if(startpos>=Y[i]&&(startpos-Y[i])%X[i]==0)//这是(*)的后续推理  (***)
				{
					return 1;
				}
				else//这是(*)的后续推理
				{
					for(int j=0;j<E;++j)
					{
						if(HasCommon[i][j])        (****)
						{
							for(int fl=Y[j];fl<F;fl+=X[j])    (*****)
							{
								if(DP(startpos,fl)==1)
									return 1;
							}
						}
					}                     
				}
			}
		}
	}
	return 0;
}

int main()
{
	fin>>N;
	for(int i=0;i<N;++i)
	{
		fin>>F>>E>>A>>B;
		Init();
		if(A<=B);
		else
		{
			int temp=A;
			A=B;
			B=temp;
		}
		for(int j=0;j<E;++j)
			fin>>X[j]>>Y[j];
		if(DP(A,B)==1)
			cout<<"It is possible to move the furniture."<<endl;
		else
			cout<<"The furniture cannot be moved."<<endl;
	}
	system("pause");
	return 0;
}

下面来讨论(*)中的原因。我们看只要(**)成立就把j号电梯标注正已处理,而不管(***)是否成立,这是因为如果(***)成立,则j号电梯能到达起点楼层,这时可以输出答案了。如果不成立的话,则j号电梯永远不能到达起始层,以后的讨论无论j号电梯能否满足(**),因为已经判断j永远不能满足(***),就可以不考虑了。所以只要满足(**),就标注已处理
(*****)可以化简,有点麻烦,先不化简了,就这样循环吧


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章