USACO / Camelot (BFS无权图最短路)

Camelot亚瑟王的宫殿

IOI 98

很久以前,亚瑟王和他的骑士习惯每年元旦去庆祝他们的友谊。为了纪念上述事件,我们把这些是看作是一个有一人玩的棋盘游戏。有一个国王和若干个骑士被放置在一个由许多方格组成的棋盘上,没有两个骑士在同一个方格内。

描述

这个例子是标准的8*8棋盘

                   棋盘.jpg

国王可以移动到任何一个相邻的方格,从下图中黑子位置到下图中白子位置前提是他不掉出棋盘之外。

                          国王.jpg

一个骑士可以从下图中黑子位置移动到下图中白子位置(走“日”字形) 但前提是他不掉出棋盘之外。

                      骑士.jpg

在游戏中,玩家可在每个方格上放不止一个棋子,假定方格足够大,任何棋子都不会阻碍到其他棋子正常行动。

玩家的任务就是把所有的棋子移动到同一个方格里——用最小的步数。为了完成这个任务,他必须按照上面所说的规则去移动棋子。另外,玩家可以选择一个骑士跟国王从他们两个相遇的那个点开始一起行动,这时他们按照骑士的行动规则行动,其他的单独骑士则自己一直走到集中点。骑士和国王一起走的时候,只算一个人走的步数。

写一个程序去计算他们集中在一起的最小步数,而且玩家必须自己找出这个集中点。当然,这些棋子可以在棋盘的任何地方集合。

格式

PROGRAM NAME: camelot

INPUT FORMAT

(file camelot.in)

第一行: 两个用空格隔开的整数:R,C 分别为棋盘行和列的长。不超过26列,30行。

第二行..结尾: 输入文件包含了一些有空格隔开的字母/数字对,一行有一个或以上。第一对为国王的位置,接下来是骑士的位置。可能没有骑士,也可能整个棋盘都是骑士。行从1开始,列从大写字母A开始。

OUTPUT FORMAT

(file camelot.out)

单独一行表示棋子集中在一个方格的最小步数。

SAMPLE INPUT

8 8
D 4
A 3 A 8
H 1 H 8

国王位置在D4。一共有四个骑士,位置分别是A3,A8,H1和H8。

SAMPLE OUTPUT

10

SAMPLE OUTPUT ELABORATION

他们集中在B5。 
骑士1: A3 - B5 (1步)  
骑士2: A8 - C7 - B5 (2步) 
骑士3: H1 - G3 - F5 - D4 (此时国王开始与这个骑士一起走) - B5 (4步) 
骑士4: H8 - F7 - D6 - B5 (3步) 
1 + 2 + 4 + 3 = 10步


分析:
  
  被这道BFS不带权图的最短路水题卡了三天,提交了80次。。。。。。就这样弱成渣了。。。。。。。。
  这道题其实思路很简单,先求出每个点到所有点的最短路,然后枚举集合点,枚举接国王的骑士,枚举接国王的点,算出需要的距离。
    总距离=Min{所有骑士到集合点的距离和-接国王的骑士到集合点的距离+国王到骑士接他的点的距离+骑士到接国王点的距离+其实从接国王的点走到集合点的距离}    (当然太朴素就铁定超时了)
  然后开始处理各个细节。
  首先求最短路,一开始脑子没动当然就想到用Dijkstra求(我有多沙茶。。。),当然O(v*v^2)铁定要超时啊,所以用heap+Dijkstra做了一下。。。果然还是超时。。。这时候我终于缓过神来,这是无权图啊!求无权图的最短路就从每一个点开始走一遍BFS就出来了啊!。。。
  然后是枚举的问题,朴素枚举当然O(n^3)超时,然后观察到这个图最大是30*26,然后估计一下最远的骑士和国王,估算后发现接国王的点应该在国王周围5格内,(这题数据弱,2格内就可以AC了,或者2格是对的?)。然后就胡乱AC了。。。




USER: Zhipeng ZHANG [138_3531] TASK: camelot LANG: C++ Compiling... Compile: OK Executing... Test 1: TEST OK [0.032 secs, 14608 KB] Test 2: TEST OK [0.032 secs, 14608 KB] Test 3: TEST OK [0.032 secs, 14608 KB] Test 4: TEST OK [0.054 secs, 14608 KB] Test 5: TEST OK [0.130 secs, 14608 KB] Test 6: TEST OK [0.184 secs, 14608 KB] Test 7: TEST OK [0.032 secs, 14608 KB] Test 8: TEST OK [0.043 secs, 14608 KB] Test 9: TEST OK [0.810 secs, 14608 KB] Test 10: TEST OK [0.281 secs, 14608 KB] Test 11: TEST OK [0.032 secs, 14608 KB] Test 12: TEST OK [0.032 secs, 14608 KB] Test 13: TEST OK [0.032 secs, 14608 KB] Test 14: TEST OK [0.043 secs, 14608 KB] Test 15: TEST OK [0.043 secs, 14608 KB] Test 16: TEST OK [0.032 secs, 14608 KB] Test 17: TEST OK [0.032 secs, 14608 KB] Test 18: TEST OK [0.032 secs, 14608 KB] Test 19: TEST OK [0.605 secs, 14608 KB] Test 20: TEST OK [0.032 secs, 14608 KB] All tests OK.

Your program ('camelot') produced all correct answers! This is your submission #80 for this problem. Congratulations!

 

/*
ID:138_3531
LANG:C++
TASK:camelot
*/

#include<fstream>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<fstream>
#include<queue>
#include<climits>
#include<vector>
#include<map>
#include<cmath>

using namespace std;

int Max(int a,int b)    {   return a>b?a:b;  }
int Min(int a,int b)    {   return a<b?a:b;  }

int n,m;
int cost[40][30][40][30];
int dist[40][30][40][30];
int d[8][2]={{-1,-2},{-2,-1},{-2,1},{-1,2},{1,2},{2,1},{2,-1},{1,-2}};


struct people
{
    int x,y;
}k[1200];
int knum;

people king;
int ans=INT_MAX;
int all_k_dist[40][30];         //以i,j为集合点的所有骑士距离和

void init(int n,int m)
{
    memset(cost,127,sizeof(cost));
    memset(dist,10,sizeof(dist));
    for (int x=0;x<n;x++)
        for (int y=0;y<m;y++)
        {
            int dx,dy;
            for (int i=0;i<8;i++)
            {
                dx=d[i][0];
                dy=d[i][1];
                if (x+dx>=0 && x+dx<n && y+dy>=0 && y+dy<m)
                {
                    cost[x][y][x+dx][y+dy]=1;
                    cost[x+dx][y+dy][x][y]=1;
                }
            }
        }
    return ;
}

queue < pair <int,int> > Q;

void bfs(int x,int y)
{

    int vis[40][30];
    memset(vis,0,sizeof(vis));
    while(!Q.empty())
        Q.pop();
    Q.push(make_pair(x,y));
    dist[x][y][x][y]=0;
    vis[x][y]=1;
    while(!Q.empty())
    {
        int kx=Q.front().first;
        int ky=Q.front().second;
        Q.pop();
        for (int i=0;i<8;i++)
        {
            int dx=kx+d[i][0];
            int dy=ky+d[i][1];
            if (dx>=0 && dx <n && dy>=0  && dy<m && !vis[dx][dy])
            {
                dist[x][y][dx][dy]=dist[x][y][kx][ky]+1;
                Q.push(make_pair(dx,dy));
                vis[dx][dy]=1;
            }
        }
    }
    return;
}

int main()
{
    ifstream fin("camelot.in");
    ofstream fout("camelot.out");
    //scanf("%d%d",&n,&m);
    fin>>n>>m;
    init(n,m);
    char a;
    int b;
    //scanf("%1s%d",&a,&b);
    fin>>a>>b;
    king.x=b-1;
    king.y=a-'A';


    while(fin>>a>>b)
    {
        k[knum].y=a-'A';
        k[knum++].x=b-1;
    }

    int king_dist[40][30];

    for (int i=0;i<n;i++)
        for (int j=0;j<m;j++)
        {
            int x=abs(double(king.x-i));
            int y=abs(double(king.y-j));
            king_dist[i][j]=Max(x,y);
        }

    for (int i=0;i<n;i++)
        for (int j=0;j<m;j++)
            bfs(i,j);

    for (int i=0;i<n;i++)
        for (int j=0;j<m;j++)
        {
            for (int p=0;p<knum;p++)
            {
                all_k_dist[i][j]+=dist[k[p].x][k[p].y][i][j];
            }
        }

    if (!knum)
    {
        for (int i=0;i<n;i++)
            for (int j=0;j<m;j++)
            {
                ans=Min(ans,king_dist[i][j]);
            }
    }

    for (int p=0;p<knum;p++)                                //枚举接国王的骑士
        for (int ix=king.x-2;ix<=king.x+2;ix++)             //枚举接国王的点
            for (int jx=king.y-2;jx<=king.y+2;jx++)
                if (ix>=0 && ix<n && jx>=0 && jx<m)
                for (int i=0;i<n;i++)                       //枚举集合点
                    for (int j=0;j<m;j++)
                    {
                        ans=Min(ans,all_k_dist[i][j]-dist[i][j][k[p].x][k[p].y]+dist[ix][jx][i][j]+dist[ix][jx][k[p].x][k[p].y]+king_dist[ix][jx]);
                    }

    fout<<ans<<endl;
    return 0;
}

 

 

posted @ 2012-08-02 13:50  AbandonZHANG  阅读(724)  评论(0编辑  收藏  举报