圆桌骑士问题

    很多世纪以前,阿瑟王和他的圆桌武士常在每年元旦聚会庆祝他们的友谊。我们用一个单人玩的棋盘游戏去纪念这个史实:一个国王和多个武士被随机放在8X8的正方形棋盘的不同方格上。只要不越出棋盘,国王可以移至与之相邻的方格内,只要不越出棋盘,武士可以跳日字,在棋局当中,选手可以在同一方格内摆放多个棋子,选手的目标是在尽可能少的步数内把所有的棋子集中到同一方格。为此,他必须按前述方法去移动棋子。此外,当国王和一个或多个武士位于同一方格内时,选手可以选择此后让国王跟随其中一个武士一同向聚会终点移动,就象移动单个武士一样。任务:写出一个程序去计算选手要实现聚会所需最少的移动次数。
输入数据:文件camelot.in包括了以字符串表示的棋盘初始状态。该字符串包含了一串最多有64个不同的棋子位置:首先是国王的位置,而随后是武士们的位置。每个位置由一对字母-数字表示:字母表示棋盘水平坐标,而数字表示棋盘垂直坐标。
输入实例:
D4A3A8H1H8
输出数据:
文件camelot.out必须包含单一的一行,以一个正整数表示选手要实现聚会所需最少的移动次数。
输出实例:
10

 

 

 

 

分析:枚举+floyd

 

点——方格

边——马步边、王步边

国王与骑士相遇点:携带点

 

设D[x1,y1,x2,y2]——任意两点之间的最短路(骑)

proc. 求D值

 D[]全置∞

 D[x1,y1,x1,y1]置0           //同一点最短路为0

d[]两点之间有马步关系 置1

用Floyd 求D[]的值

 

主:

min=∞;

枚举“聚集点”

    Tot=n个骑士到聚集点的总步数

    if tot>=min 则 continue;

    枚举n个骑士

        枚举携带点位置        //注意:这里枚举点都是两重循环。

        if tot-带王骑士到聚集点步数+带国王骑士到“携带点”步数+再到聚集点步数+国王到“携带点”步数<min then 更新;

输出min;

 

*判断马步关系只需看横坐标绝对值*纵坐标绝对值是否为2

*国王到“携带点”步数=max{横坐标差,纵坐标差}

 

下面是写得很烂的程序:

ContractedBlock.gif ExpandedBlockStart.gif Code
#include<stdio.h>
#include
<stdlib.h>
#include
<string.h>
#include
<math.h>
int kgx,kgy,i,j,k,l,n,x,y,tot,min;
int d[10][10][10][10],a[70],b[70];
char s[200];
int max(int a,int b){
    
return a>b?a:b;
}

void Floyd(){
     
int i,j,k,l,kx,ky,ix,iy,jx,jy;
     memset(d,
30000,sizeof(d));
     
for (i=1;i<=8;i++)
         
for (j=1;j<=8;j++)
             d[i][j][i][j]
=0;
     
for (i=1;i<=8;i++)
         
for (j=1;j<=8;j++)
             
for (k=1;k<=8;k++)
                 
for (l=1;l<=8;l++)
                     
if (abs(i-k)*abs(j-l)==2)
                         d[i][j][k][l]
=1;
     
for (kx=1;kx<=8;kx++)
         
for (ky=1;ky<=8;ky++)         
             
for (ix=1;ix<=8;ix++)
                 
for (iy=1;iy<=8;iy++)
                     
for (jx=1;jx<=8;jx++)
                         
for (jy=1;jy<=8;jy++){
                             
if (d[ix][iy][jx][jy]>(d[ix][iy][kx][ky]+d[kx][ky][jx][jy]))
                                 d[ix][iy][jx][jy]
=d[ix][iy][kx][ky]+d[kx][ky][jx][jy];
                         }
}

int main(){
    freopen(
"camelot.in","r",stdin);
    freopen(
"camelot.out","w",stdout);
    gets(s);
    kgx
=s[0]-64;
    kgy
=s[1]-48;
    
for (i=2;i<strlen(s);i++){
        
if (i%2==0) a[i/2]=s[i]-'A'+1;
        
else b[i/2]=s[i]-'0';
    }
    
    n
=strlen(s)/2-1;    
    Floyd();
    
    min
=32767;
    
for (i=1;i<=8;i++)
        
for (j=1;j<=8;j++){
            tot
=0;
            
for (k=1;k<=n;k++){
                tot
+=d[a[k]][b[k]][i][j];
                
if (tot>=min) continue;
            }
            
for (k=1;k<=n;k++)     
                
for (x=1;x<=8;x++)  
                    
for (y=1;y<=8;y++)
                        
if (tot-d[a[k]][b[k]][i][j]+d[a[k]][b[k]][x][y]+d[x][y][i][j]+max(abs(kgx-x),abs(kgy-y))<min){
                            min
=tot-d[a[k]][b[k]][i][j]+d[a[k]][b[k]][x][y]+d[x][y][i][j]+max(abs(kgx-x),abs(kgy-y));
                        }
        }
    printf(
"%d",min);
    
return 0;
}

 

转载于:https://www.cnblogs.com/yanrui7098/archive/2009/11/08/1598408.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值