USACO Camelot

  利用一个dis数组表示骑士从点(i,j)到点(x,y)的最短距离,预处理这个数组,用bfs将floyd算法简化为O(N^2),然后对于每一点枚举所有骑士走到此处的最短距离和,在枚举每个骑士接国王所需最短路径,注意判断此点骑士是否可达,其最小值即可。

/*
ID: jinusac1
PROG: camelot
LANG: C++
*/
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <queue>
using namespace std;
typedef struct Position{
	int x,y;
}Pos;
struct KING{
	int x,y;
	int cost;
}king[25];
int sizek=1;
int dis[27][31][27][31]={0},size1=0,R1,C;
int dir[8][2]={2,1,2,-1,-2,1,-2,-1,1,2,1,-2,-1,2,-1,-2};
int one[8][2]={1,1,1,-1,-1,1,-1,-1,1,0,-1,0,0,1,0,-1};
int two[16][2]={2,0,-2,0,0,2,0,-2,2,1,2,-1,-2,1,-2,-1,1,2,1,-2,-1,2,-1,-2,2,2,2,-2,-2,2,-2,-2};
Pos pos[800];
inline bool is(int x,int y)
{
	if(x<=0||x>R1||y<=0||y>C) return 0;
	return 1;
}
void bfs(int sx,int sy)
{
	bool have[27][31]={false};
	Pos t;
	t.x=sx;
	t.y=sy;
	have[sx][sy]=true;
	queue<Pos> h;
	h.push(t);
	while(!h.empty()){
		int tx=h.front().x,ty=h.front().y;
		h.pop();
		for(int i=0;i<8;i++){
			int rx=tx+dir[i][0],ry=ty+dir[i][1];
			if(is(rx,ry)&&!have[rx][ry]){
				have[rx][ry]=true;
				dis[sx][sy][rx][ry]=dis[sx][sy][tx][ty]+1;
				t.x=rx;t.y=ry;
				h.push(t);
			}
		}
	}
}
int main()
{
	//freopen("in.txt","r",stdin);
	freopen("camelot.in","r",stdin);
	freopen("camelot.out","w",stdout);
	cin>>C>>R1;
	char t;
	int kx,ky;
	cin>>t>>ky;
	kx=t-'A'+1;
	int tx,ty;
	while(cin>>t>>ty){
		if(t=='!') break;
		tx=t-'A'+1;
		pos[size1].x=tx;
		pos[size1].y=ty;
		int tttt=size1;
		size1++;
	}
	for(int i=1;i<=R1;i++)
		for(int j=1;j<=C;j++) bfs(i,j);
	king[0].cost=0;king[0].x=kx;king[0].y=ky;
	for(int i=0;i<8;i++) if(is(kx+one[i][0],ky+one[i][1])){
		king[sizek].cost=1;
		king[sizek].x=kx+one[i][0];
		king[sizek].y=ky+one[i][1];
		sizek++;
	}
	for(int i=0;i<16;i++) if(is(kx+two[i][0],ky+two[i][1])){
		king[sizek].cost=2;
		king[sizek].x=kx+two[i][0];
		king[sizek].y=ky+two[i][1];
		sizek++;
	}
	int ans=0x7FFFFFFF;
	for(int x=1;x<=R1;x++)
		for(int y=1;y<=C;y++){
			int sum=0;
			bool mark=true;
			for(int i=0;i<size1;i++){
				if((x!=pos[i].x||y!=pos[i].y)&&!dis[pos[i].x][pos[i].y][x][y]){
					mark=false;
					break;
				}
				sum+=dis[pos[i].x][pos[i].y][x][y];
			}
			if(!mark) continue;
			if((abs(x-kx)+abs(y-ky)+sum)<ans) ans=abs(x-kx)+abs(y-ky)+sum;
			for(int i=0;i<size1;i++){
				int temp1=sum-dis[pos[i].x][pos[i].y][x][y];
				for(int j=0;j<sizek;j++) {
					if((king[j].x!=pos[i].x||king[j].y!=pos[i].y)&&!dis[pos[i].x][pos[i].y][king[j].x][king[j].y])
						continue;
					int temp2=temp1+dis[pos[i].x][pos[i].y][king[j].x][king[j].y];
					temp2+=dis[king[j].x][king[j].y][x][y];
					temp2+=king[j].cost;
					if(temp2<ans) ans=temp2;
				}
			}
		}
	cout<<ans<<endl;
	return 0;
}


 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值