usaco Camelot

这道题目确实是挺难想的——对于我而言,如果不看别人的思路,我也是想不出的。

我现在采用的思路是:

枚举国王和骑士们相遇的地点(最多26*30),及可能会带上国王的好心骑士及他们相遇的地点(坐标)。

呵呵……这就得想明白一点,如下图所示


如果某个骑士要去接国王,那么应该这个骑士应到国王附近一格距离(图中蓝色部分)或国王当前所在坐标位置(图中红色部分)。

当然也要考虑国王自己跑到终点的情况。

下面是我代码,仅供参考:

/*
ID: guo geer
PROG: camelot
LANG: C++
*/
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<fstream>
#include<cmath>
using namespace std;

int kingMove [9][2] = {{0, 1}, {1, 1}, {1, 0}, {1, -1}, {0, -1}, {-1, -1}, {-1, 0}, {-1, 1}, {0, 0}};
int knightMove [8][2] = {{1, 2}, {2, 1}, {2, -1}, {1, -2}, {-1, -2}, {-2, -1}, {-2, 1}, {-1, 2}};
int dist[27][31][27][31];
int knightLocation[2000][2];

void bfs(int board[][31], int x0, int y0, int X, int Y)
{
     int f, r, r1;
     int q[10000][2];
     q[0][0] = x0, q[0][1] = y0;
     board[x0][y0] = 0;
     f=r=r1=0;
     
     int steps = 1;
     while(true)
     {
          r ++;
          while(f != r)
          {
               int x, y;
               for(int i=0; i<8; i++)
               {
                    x = q[f][0]+knightMove[i][0];
                    y = q[f][1]+knightMove[i][1];
                    if(x>0 && x<=X && y>0 && y<=Y && board[x][y] == -1)
                    {
                          q[++r1][0] = x;
                          q[r1][1] = y;
                          board[x][y] = steps;
                    }
               }
         f++;
    }
    steps ++;
    if(r1 < r) return ;
    r = r1;
     }
}

int main()
{
    freopen("camelot.in", "r", stdin);
    freopen("camelot.out", "w", stdout);
    
    int x0, y0, X, Y;
    char ch;
    scanf("%d %d", &Y, &X);
    scanf(" %c %d", &ch, &y0);
    x0 = ch-'A'+1;
    
    memset(dist, -1, sizeof(dist));
    for(int i=1; i<=X; i++)
    for(int j=1; j<=Y; j++) bfs(dist[i][j], i, j, X, Y);
    
    int x, y;
    int n = 0;
    while(scanf(" %c %d", &ch, &y) != EOF)
    {
            x = ch-'A'+1;
            knightLocation[n][0] = x;
            knightLocation[n][1] = y;
            n ++;
    }
    int res = 1000000;

    for(int i=1; i<=X; i++)
    {
        for(int j=1; j<=Y; j++)
        {
                int s0 = 0;
                int isAllPositive = 1;
                for(int k=0; k<n; k++) 
                {                       
                       int tx, ty;
                       tx = knightLocation[k][0];
                       ty = knightLocation[k][1];
                       s0 += dist[i][j][tx][ty];   
                       if(dist[i][j][tx][ty] < 0) isAllPositive = 0;                                                      
                }                 
                if(isAllPositive == 0) continue;   
                                                         
                for(int k=0; k<n; k++)
                {
                        int tx, ty;
                        tx = knightLocation[k][0];
                        ty = knightLocation[k][1];
                        
                        for(int dir=0; dir<9; dir++)
                        {
                            int x1 = kingMove[dir][0]+x0;
                            int y1 = kingMove[dir][1]+y0;
                            if(x1 < 1 || x1 > X || y1 < 1 || y1 > Y) continue;  
                            if(dist[i][j][tx][ty] < 0 || dist[i][j][x1][y1] < 0 || dist[x1][y1][tx][ty] < 0) continue;                                                    
                            int s = s0 - dist[i][j][tx][ty] + dist[i][j][x1][y1] + dist[x1][y1][tx][ty];
                             if(dir != 8) s ++;
                            if(res > s) res = s;                           
                        }
                        
                        if(res > max(abs(x0-tx),abs(y0-ty))+s0) res = max(abs(x0-tx),abs(y0-ty))+s0;
                }
        }
    }
    if(n == 0) res = 0;    
    printf("%d\n", res);    
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值