poj 1178 Camelot

题目大意:

有一种棋盘游戏,棋盘有8x8共64个方格,有两种棋子:国王和骑士,国王只有一个,骑士可以有多个。国王每移动一步可以从当前位置移动到八个方向的相邻方格(共有8种走法),移动的时候不能越界。骑士也是8种走法,但走的是“日”字,移动的时候也不能越界。当国王遇到骑士时,骑士可以带上国王,该骑士和国王看作一个骑士,按骑士走法走,每走一步只算一步(即国王从此可以忽略)。现在要求出将棋盘上所有骑士以及国王移动到相同方格需要的最少移动步数。初始时各个骑士和国王均在不同的方格。

解题思路:

使用枚举法

如果确定了最终的位置国王和骑士相遇的位置国王与哪个骑士相遇三个要素,则最少移动步数就确定了。

最终的位置共有64种,国王和骑士相遇的位置也有64种,设有N个骑士,则国王与哪个骑士相遇有N种,则枚举O(64*64*N)

对某个最终位置dst,相遇位置m,遇到国王的骑士k:

  1 计算所有骑士到dst的最少移动步数。

  2 加上国王移动到m的最少移动步数。

  3 加上骑士k经过m到dst的最少移动步数。

  4 减去骑士k到dst的最少移动步数。(骑士k在第1步中也算了一遍,所以要减去)

  5 如果总的最少步数比当前已经求出的最少步数少,则更新最少步数。

枚举完后输出最后结果。

对于国王和骑士从某一点到另外一点的最少移动步数,采用floyd算法可以求出。

#include <string>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>

using namespace std;

string s;
int p[65],t;
int G1[65][65],G2[65][65];
int move1[][2] = {{-1,-1},{-1,0},{-1,1},{0,-1},{0,1},{1,-1},{1,0},{1,1}};
int move2[][2] = {{-2,-1},{-2,1},{-1,-2},{-1,2},{1,-2},{1,2},{2,-1},{2,1}}; 

bool IO(int x, int y){
	if(x < 0 || x >= 8 || y < 0 || y >= 8)
		return false;
	return true;
}

int get_position(int x, int y){
	return x + y * 8;
}

void get_xy(int i, int &x, int &y){
	x = i % 8;
	y = i / 8;	
}

void Init(){//建图
	for(int i=0; i<64; i++){
		for(int j=0; j<64; j++)
			G1[i][j] = G2[i][j] = 0x3f3f3f3f;
		G1[i][i] = G2[i][i] = 0;
	}
	for(int i=0; i<64; i++){
		int x, y;
		int dx, dy;
		int next_position;
		get_xy(i, x, y);
		for(int k=0; k<8; k++){
			dx = x + move1[k][0];
			dy = y + move1[k][1];
			if(IO(dx, dy)){
				next_position = get_position(dx, dy);
				G1[i][next_position] = 1;
			}
			dx = x + move2[k][0];
			dy = y + move2[k][1];
			if(IO(dx, dy)){
				next_position = get_position(dx, dy);
				G2[i][next_position] = 1;
			}
		}	
	}
}

void Floyd(){//全源最短路
	for(int k=0; k<64; k++)
		for(int i=0; i<64; i++)
			for(int j=0; j<64; j++){
				if(G1[i][j] > G1[i][k] + G1[k][j])
					G1[i][j] = G1[i][k] + G1[k][j];
				if(G2[i][j] > G2[i][k] + G2[k][j])
					G2[i][j] = G2[i][k] + G2[k][j];
			}
}

int main(){
	cin >> s;
	int n = s.size();
	t = 0;
	for(int i=0; i<n; i+=2)//将点的坐标转化成标号
		p[t++] = (s[i]-'A') + (s[i+1]-'1')*8;
	Init();
	Floyd();
	int ans = 0x3f3f3f3f, sum;
	for(int dst = 0; dst < 64; dst++){
		for(int m = 0; m < 64; m++){
			for(int k=1; k<t; k++){
				sum = 0;
				for(int i=1; i<t; i++) sum += G2[p[i]][dst];
				sum += G1[p[0]][m];
				sum += (G2[p[k]][m] + G2[m][dst]);
				sum -= G2[p[k]][dst];
				ans = min(ans, sum);
			}
		}
	}
	cout << ans << endl;
	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值