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永遠不能滿足(***),就可以不考慮了。所以只要滿足(**),就標註已處理
(*****)可以化簡,有點麻煩,先不化簡了,就這樣循環吧


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