poj 1178 Camelot floyd+枚举

参考:

http://blog.csdn.net/lijiecsu/article/details/7579855

使用枚举法

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

最终的位置共有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算法可以求出。


code:写的很乱

#include <iostream>
#include <stdio.h>
#include <cstring>
using namespace std;

#define inf (1000000000)
#define MAX_N 64
int kdis[MAX_N][MAX_N];
int nightdis[MAX_N][MAX_N]; 

struct move
{
	int x;
	int y;
}NIGHTMOVE[]={ {-2,1},{2,1},{-2,-1},{2,-1},{1,2},{-1,2},{1,-2},{-1,-2} };

struct move KMOVE[]= { {-1,1},{0,1},{1,1},{-1,0},{1,0},{-1,-1},{0,-1},{1,-1}};

bool valid(int x,int y)
{
	if( x >= 0 && x < 8 && y >= 0 && y < 8)
		return true;

	return false;
}

int nightfloyd()
{
	for(int i=0;i<MAX_N;i++)
		for(int j=0;j<MAX_N;j++)
		{
			nightdis[i][j]=inf;
			kdis[i][j]=inf;

			if( i == j)
			{
				nightdis[i][j]=0;
				kdis[i][j]=0;
			}
		}

	for(int i=0;i<MAX_N;i++)
	{	
		int x =  i %8;
		int y =  i/8;
		for(int m=0;m< 8;m++)
		{
			int mx = x + NIGHTMOVE[m].x;
			int my = y + NIGHTMOVE[m].y;

			int kmx = x + KMOVE[m].x;
			int kmy = y + KMOVE[m].y;

			if(valid(mx,my))
			{
				int j=( my * 8 + mx);
				nightdis[i][j] = 1;

			}
			if(valid(kmx,kmy))
			{
				int j = (kmy *8) + kmx;
				kdis[i][j] = 1;
			}
		}
	}
	for(int k=0;k<MAX_N;k++)
	{
		for(int i=0;i<MAX_N;i++)
		{
			for(int j=0;j<MAX_N;j++)
			{
				
				kdis[i][j] = min(kdis[i][k]+kdis[k][j],kdis[i][j]);
				nightdis[i][j] = min(nightdis[i][k]+nightdis[k][j],nightdis[i][j]);
				//printf("********nightdir[%d][%d]=%d\n",i,j,nightdis[i][j]);
			}
		}
	}
    for(int i=0;i<64;i++)
    {
	    for(int j=0;j<64;j++)
	   {
		  //printf("king[%d][%d]=%d\n",i,j,kdis[i][j]); 
		  //printf("kight[%d][%d]=%d\n",i,j,nightdis[i][j]);
	   }
    }
}
int K=0;
int I[MAX_N]; //I[0]表示国王的起点位置
int get_index(char c,char n)
{
	//I[0] = (str[0] - 'A') + ( str[1] -1)*8;
	
	return (c - 'A') + ( n -'1') *8;
}

int knight_sum_but_k(int k,int f) //除了k,其它所有骑士到终点f的最短距离之和
{
	int sum = 0;
	for(int i=1;i<=K;i++)
	{
		if( i==k)
			continue;
		sum += nightdis[I[i] ][f];
	}

	//printf("knight_sum_but_k k=%d,f=%d,sum=%d\n",k,f,sum);
	return sum;

}

int king_to(int king,int f)
{
	return kdis[king][f];
}

int knight_to(int night,int f)
{
	return nightdis[night][f];
}

int main()
{
	string str;
	nightfloyd();
	while(cin>>str)
	{
		int minret = inf;
		int L=str.length();
		
		I[0] = get_index(str[0],str[1]);
		for(int l=2;l<L;l += 2)
		{
			K++;
			I[K] = get_index(str[l],str[l+1]);
		}
		
		//printf("K=%d\n",K);

		for(int i=0;i<64;i++)
		{
			for(int j=0;j<64;j++)
			{
				for(int k=1;k<=K;k++)
				{
					//最终i,国王与k相遇在j
					int sum = 0;

					sum += knight_sum_but_k(k,i);

					sum += king_to(I[0],j);

					sum += knight_to(I[k],j);

					sum += knight_to(j,i);

					if(sum < minret)
						minret = sum;

					//printf("i=%d,j=%d,k=%d,sum=%d\n",i,j,k,sum);

				}
			}
		}

		cout<<minret<<endl;
	}
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值