usaco3.3.4亚瑟王的宫殿

76 篇文章 0 订阅

一个万无一失的方法

对于骑士带王去会合的情况,枚举王的原位置和八个方向,也就是说王和骑士的汇合点相对于王的原位置为上下左右或者斜45度方向。

比如在8*8的棋盘上,王的位置用k表示,需要枚举的带王的点用1表示,其余点用0表示则有下图:

0 0 1 0 0 1 0 0
1 0 1 0 1 0 0 0
0 1 1 1 0 0 0 0
1 1 k 1 1 1 1 1
0 1 1 1 0 0 0 0
1 0 1 0 1 0 0 0
0 0 1 0 0 1 0 0
0 0 1 0 0 0 1 0

对于其他带王点的情况,总可以等效为以上情况之一,这样枚举不会超时。

需要注意的是,输入时的R,C分别代表列数和行数。

主要用bfs,搜出对于每一个knight到达每一个格子所需的步数。(调试了一个下午,结果是字母打错了,好想骂人啊)

具体思路看代码吧。

#include<cstdio>
#include<iostream>
#include <queue>
#include <cmath>
#include <algorithm>
using namespace std;
struct aaaa{int x,y,d;};
int moveking[8][2]={{-1,0},{-1,1},{0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1}};
int moveknight[8][2]={{-2,1},{-1,2},{1,2},{2,1},{2,-1},{1,-2},{-1,-2},{-2,-1}};
int king[2],knight[1041][2],kingdist[27][41];
int disttoking[200][27][41];
int dist[1041][27][41],zonghe[27][41],R,C,numknight=1,num=0;
void bfs(int s[2],int move[8][2],int dist1[27][41]);
int main()
{
    //freopen("camelot.in","r",stdin);
    //freopen("camelot.out","w",stdout);
    cin>>C>>R;
    char a;
    cin>>a>>king[1];
    king[0]=a-64;
    while(cin>>a>>knight[numknight][1])
    {
        knight[numknight][0]=a-64;
        numknight++;
    }
    numknight--;
    bfs(king,moveking,kingdist);
    for(int i=0;i<8;i++)
    {
        int s[2];
        s[0]=king[0]+moveking[i][0];
        s[1]=king[1]+moveking[i][1];
        while(s[0]>0&&s[0]<=R&&s[1]>0&&s[1]<=C)
        {
            bfs(s,moveknight,disttoking[num++]);
            s[0]=s[0]+moveking[i][0];
            s[1]=s[1]+moveking[i][1];
        }
    }
    bfs(king,moveknight,disttoking[num]);
    for(int i=1;i<=numknight;i++)
    {
       bfs(knight[i],moveknight,dist[i]);
    }
    int min1=99999999,lala;
    for(int i=1;i<=R;i++)
        for(int j=1;j<=C;j++)
        for(int k=1;k<=numknight;k++)
        zonghe[i][j]+=dist[k][i][j];
    for(int i=1;i<=R;i++)
        for(int j=1;j<=C;j++)
       {
           lala=zonghe[i][j]+kingdist[i][j];
           if(lala<min1)min1=lala;
           for(int l=1;l<=numknight;l++)
           {
               lala=zonghe[i][j]-dist[l][i][j];
               lala+=dist[l][king[0]][king[1]];
               lala+=disttoking[num][i][j];
               if(lala<min1)min1=lala;
               int bu=0;
               for(int i1=0;i1<8;i1++)
               {
                   int s[2],shu=1;
                   s[0]=king[0]+moveking[i1][0];
                   s[1]=king[1]+moveking[i1][1];
                   while(s[0]>0&&s[0]<=R&&s[1]>0&&s[1]<=C)
                   {
                       lala=disttoking[bu][i][j];
                       lala+=dist[l][s[0]][s[1]];
                       lala+=shu;
                       lala+=(zonghe[i][j]-dist[l][i][j]);
                       shu++;
                       bu++;
                       if(lala<min1)min1=lala;
                       s[0]=s[0]+moveking[i1][0];
                       s[1]=s[1]+moveking[i1][1];
                   }


               }
           }
       }
    cout<<min1<<endl;
 return 0;
}
void bfs(int s[2],int move[8][2],int dist1[27][41])
{
    bool done[27][41];
    queue<aaaa>q;
    while(!q.empty())q.pop();
    for(int i=1;i<=R;i++)for(int j=1;j<=C;j++){done[i][j]=false;dist1[i][j]=99999999;}
    dist1[s[0]][s[1]]=0;
    q.push((aaaa){s[0],s[1],0});
    done[s[0]][s[1]]=true;
    while(!q.empty()){
        aaaa key=q.front();
        q.pop();
        for(int i=0;i<8;i++)
        {
            aaaa kk;
            kk.x=key.x+move[i][0];
            kk.y=key.y+move[i][1];
            if(kk.x>0&&kk.x<=R&&kk.y>0&&kk.y<=C&&!done[kk.x][kk.y]){
                done[kk.x][kk.y]=true;
                dist1[kk.x][kk.y]=key.d+1;
                kk.d=key.d+1;
                q.push(kk);
            }
        }
}
}

可能这个更清楚:

#include<stdio.h>
#include<stdlib.h>
 
#define LENQUE 781
#define INFI 500
FILE *fin,*fout;
int R,C;
int dist[781][31][27];
int total[31][27];
int distking[31][27];
int distride[120][31][27];
int numride;
int king[2];
int numknight;
int knight[781][2];
int moveknight[8][2]={
	{-2,1},{-1,2},{1,2},{2,1},{2,-1},{1,-2},{-1,-2},{-2,-1}
};
int moveking[8][2]={
	{-1,0},{-1,1},{0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1}
};
int queue[LENQUE][3];
bool done[31][27];
 
void bfs(int s[2],int move[8][2],int distmemo[31][27]){
	int i,j;
	for(i=0;i<R;i++)for(j=0;j<C;j++)done[i][j]=false;
	for(i=0;i<R;i++)for(j=0;j<C;j++)distmemo[i][j]=INFI;
	distmemo[s[0]][s[1]]=0;
	done[s[0]][s[1]]=true;
	int head=0,tail=1;
	queue[0][0]=s[0];
	queue[0][1]=s[1];
	queue[0][2]=0;
	while(head!=tail){
		for(i=0;i<8;i++){
			int temp[2];
			temp[0]=queue[head][0]+move[i][0];
			temp[1]=queue[head][1]+move[i][1];
			if(temp[0]>=0&&temp[0]<R&&temp[1]>=0&&temp[1]<=C){
				if(!done[temp[0]][temp[1]]){
					queue[tail][0]=temp[0];
					queue[tail][1]=temp[1];
					queue[tail][2]=queue[head][2]+1;
					done[temp[0]][temp[1]]=true;
					distmemo[temp[0]][temp[1]]=queue[tail][2];
					tail=(tail+1)%LENQUE;
				}
			}
		}
		head=(head+1)%LENQUE;
	}
}
 
int main(){
	fin=fopen("camelot.in","r");
	fout=fopen("camelot.out","w");
	fscanf(fin,"%d %d\n",&R,&C);
	char col;
	int row;
	fscanf(fin,"%c %d",&col,&row);
	king[0]=row-1;
	king[1]=col-'A';
	while(fscanf(fin,"%c",&col)!=EOF){
		if(col==' '||col=='\n')continue;
		fscanf(fin,"%d",&row);
		knight[numknight][0]=row-1;
		knight[numknight][1]=col-'A';
		numknight++;
	}
	int i;
	bfs(king,moveking,distking);
	for(i=0;i<8;i++){
		int temp[2];
		temp[0]=king[0]+moveking[i][0];
		temp[1]=king[1]+moveking[i][1];
		while(temp[0]>=0&&temp[0]<R&&temp[1]>=0&&temp[1]<C){
			bfs(temp,moveknight,distride[numride++]);
			temp[0]=temp[0]+moveking[i][0];
			temp[1]=temp[1]+moveking[i][1];
		}
	}
	bfs(king,moveknight,distride[numride++]);
	for(i=0;i<numknight;i++){
		bfs(knight[i],moveknight,dist[i]);
	}
	int min=0x7fffffff;
	int gr,gc,ride,d,move;
	for(gr=0;gr<R;gr++)for(gc=0;gc<C;gc++){
		for(i=0;i<numknight;i++){
			total[gr][gc]+=dist[i][gr][gc];
		}
	}
	for(gr=0;gr<R;gr++)for(gc=0;gc<C;gc++){
		d=distking[gr][gc]+total[gr][gc];
		if(d<min)min=d;
		for(ride=0;ride<numknight;ride++){
			d=distride[numride-1][gr][gc];
			d+=dist[ride][king[0]][king[1]];
			d+=total[gr][gc]-dist[ride][gr][gc];
			if(d<min)min=d;
			int po=0,countking=0;
			for(i=0;i<8;i++){
				int temp[2];
				temp[0]=king[0]+moveking[i][0];
				temp[1]=king[1]+moveking[i][1];
				countking=1;
				while(temp[0]>=0&&temp[0]<R&&temp[1]>=0&&temp[1]<C){
					d=distride[po][gr][gc];
					d+=countking;
					d+=dist[ride][temp[0]][temp[1]];
					d+=total[gr][gc]-dist[ride][gr][gc];
					if(d<min)min=d;
					po++;
					countking++;
					temp[0]=temp[0]+moveking[i][0];
					temp[1]=temp[1]+moveking[i][1];
				}
			}
		}
	}
	fprintf(fout,"%d\n",min);
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值