Knight's Trip 馬在無線大棋盤上跳到指定點最小步數問題

題目描述

Problem D: Knight's Trip

In chess, each move of a knight consists of moving by two squares horizontally and one square vertically, or by one square horizontally and two squares vertically. A knight making one move from location (0,0) of an infinite chess board would end up at one of the following eight locations: (1,2), (-1,2), (1,-2), (-1,-2), (2,1), (-2,1), (2,-1), (-2,-1).

Starting from location (0,0), what is the minimum number of moves required for a knight to get to some other arbitrary location (x,y)?

輸入要求

Each line of input contains two integers x and y, each with absolute value at most one billion. The integers designate a location (x,y) on the infinite chess board. The final line contains the wordEND.

輸出要求

For each location in the input, output a line containing one integer, the minimum number of moves required for a knight to move from (0,0) to (x,y).

假如輸入

1 2
2 4
END

應當輸出

1
2


這題不能用bfs,bfs代碼如下,因爲棋盤很大,會空間不足,但可以用bfs打印出棋盤來狀況來分析,這題做了好久- -、、、、


#include<iostream>
#include<algorithm>
#include <vector>
#include<string.h>
#include<ctype.h>
#include<math.h>
using namespace std;
int map[1005][1005];
int res[1005][1005];
struct point
{
	int x,y;
};
struct point r[1005];
int dis[8][2]={{1,2},{-1,2},{1,-2},{-1,-2},{2,1},{-2,1},{2,-1},{-2,-1}};
int m,n;
void bfs()
{
	int tail=1, head=0,i,x1,y1;
	r[0].x=2;
	r[0].y=2;	
	while(tail != head)
	{
		x1=r[head].x;
		y1=r[head].y;
		for(i=0; i<8; i++)
		{
			x1+=dis[i][0], y1+=dis[i][1];
			if(map[x1][y1]==0&&res[x1][y1]==-1)
			{
				r[tail].x=x1;
				r[tail].y=y1;
				res[x1][y1] = 1 + res[x1-dis[i][0]][y1-dis[i][1]];
				tail++;
			}
			x1-=dis[i][0], y1-=dis[i][1];
		}
		head++;	
		if(res[m+2][n+2]!=-1)
			break;
	}
}
void fun();
int main()
{
    fun();
    return 0;
}
void fun()
{
	int i,j;
	while(cin>>m>>n)
	{
		memset(map,-1,sizeof(map));
		memset(res,-1,sizeof(res));
		m=abs(m);
		n=abs(n);
		if(m>n)
		{
			int temp=m;
			m=n;
			n=temp;
		}
		for(i=2;i<m+3;i++)
		{
			for(j=2;j<n+3;j++)
				map[i][j]=0;
		}
		res[2][2]=0;//棋盤0,0點
		res[3][3]=2;//棋盤1,1座標要自己賦值,否則bfs算出來是4是錯誤的,因爲我們把棋盤只考慮成第一象限的了
		bfs();
		for(i=2;i<m+3;i++)
		{
			for(j=2;j<n+3;j++)
				printf("%3d",res[i][j]);
			cout<<endl;
		}
		cout<<res[m+2][n+2]<<endl;
	}
}



可以用枚舉來解決,如下

n=2*m這種情況直接就是(m+n)/3步。
如果n<2*m但是(m+n)%3==0的話,那麼我們可以通過控制(1,2),(2,1)兩種跳法的次數達到...總數必然是(m+n)/3,然後m,n的和對3取餘是1的話,我們是不是必然可以在(m+n-1)/3步的時候跳到(m,n-1)這個點,但是不能一步跳到(m,n),回撤兩步到(m-4,n-5)這個點,我們可以用三步跳到(m,n),那麼就是原先的步數+1。餘數爲2,就是先跳到(m-1,n-1)這個地方,我們知道(0,0)到(1,1)只需要兩步,那麼(m-1,n-1)到(m,n)也就是原先步數+2.
然後考慮n>2*m,先把(0,1)的情況特殊處理一下。接着我們可以用m步跳到(m,n),那麼原問題就轉化爲(0,0)到(0,n-2*m)。當n-2*m是4的倍數的話我們可以直接(1,2)(-1,2)這個跳可以在(n-2*m)/2步到達。餘數爲1,就是(0,0)到(0,1)的問題,但是這個需要三步不是最優的,我們後撤兩步變爲(0,0)到(0,5),我們可以三步達到,那麼就是原先的步數加上1就是解。餘數爲2,我們可以分別跳一次(2,1)(-2,1)到達。餘數爲3,轉化爲(0,0)到(0,3)的問題我們可以(-1,2)(1,1)(0,3)三步到達。

#include<iostream>
#include<algorithm>
#include <vector>
#include<string.h>
#include<ctype.h>
#include<math.h>
using namespace std;
void fun();
int main()
{
    fun();
    return 0;
}
void fun()
{
	int m,n;	
	while(cin>>m>>n)
	{
		m=abs(m);
		n=abs(n);
		if(m>n)
		{
			int temp=m;
			m=n;
			n=temp;
		}
		if(2*m>=n)
		{
			if(m==n&&m==1)
				cout<<2<<endl;
			else if(m==n&&m==2)
				cout<<4<<endl;
			else
				cout<<(m+n)/3+(m+n)%3<<endl;
		}
		else
		{
			int ans=m;
			int c=(n-2*m)%4;
			ans+=c;
			ans+=(n-2*m-c)/2;
			if(n==1&&m==0)
				ans=3;
			cout<<ans<<endl;
		}
	}
}






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