usaco Camelot

题意是,国王和很多骑士在棋盘的不同位置,国王要和骑士在一点聚集。

若某个骑士和国王相遇之后,骑士和国王共同走一步,只算一步。等于是骑士背上了国王,国王不再走路。

第一遍我的算法用BFS计算出了每个骑士到棋盘上每个位置的最短距离。枚举每个点作为集合点,然后判断骑士能否在走到集合点的过程中遇上国王。依据是,国王所在点在骑士要到达的距离小于集合点,这么做其实并不能保证骑士遇见了国王,但还是骗过了5个测试点。

后来看别人才知道是国王在走两步只内就能遇见骑士。关于证明我没找到。

/*
ID: modengd1
PROG: camelot
LANG: C++
*/
#include <iostream>
#include <stdio.h>
#include <memory.h>
#include <queue>
#include <vector>
#include <algorithm>
#define MofInt 0x7fffffff
using namespace std;
int R,C;
int step[27][31][27][31];
int kingstep[27][31];
int dx[8]={1,1,-1,-1,2,2,-2,-2};
int dy[8]={2,-2,2,-2,1,-1,1,-1};
int dxk[8]={0,0,1,1,1,-1,-1,-1};
int dyk[8]={1,-1,0,1,-1,0,1,-1};
typedef pair<int,int> position;
vector<position> PoS;
position king;
struct node
{
    int x,y,step;
    node(int xx,int yy,int ss)
    {
        x=xx;y=yy;step=ss;
    }
    node(){}
};
void BFSforking()
{
    memset(kingstep,0x7f,sizeof(kingstep));
    queue<node> Q;
    Q.push(node(king.first,king.second,0));//起始点
    kingstep[king.first][king.second]=0;
    while(!Q.empty())
    {
        node now=Q.front();
        Q.pop();
        for(int j=0;j<8;j++)
        {
            node next=node(now.x+dxk[j],now.y+dyk[j],now.step+1);
            if(next.x<1||next.x>R||next.y<1||next.y>C)
                continue;
            if(kingstep[next.x][next.y]<=next.step)
                continue;
            kingstep[next.x][next.y]=next.step;
            Q.push(next);
        }
    }
}
void BFS()
{
    for(int i=1;i<=R;i++)
    {
        for(int k=1;k<=C;k++)
        {
            memset(step[i][k],0x7f,sizeof(step[i][k]));
            queue<node> Q;
            Q.push(node(i,k,0));//起始点
            step[i][k][i][k]=0;
            while(!Q.empty())
            {
                node now=Q.front();
                Q.pop();
                for(int j=0;j<8;j++)
                {
                    node next=node(now.x+dx[j],now.y+dy[j],now.step+1);
                    if(next.x<1||next.x>R||next.y<1||next.y>C)
                        continue;
                    if(step[i][k][next.x][next.y]<=next.step)
                        continue;
                    step[i][k][next.x][next.y]=next.step;
                    Q.push(next);
                }
            }
        }
    }
}
void output()
{
    if(PoS.size()==0)
    {
        cout<<0<<endl;
        return;
    }
    //计算king到所有骑士当中最近的一个的距离
    int ans=MofInt;

    //枚举集合点

    for(int i=1;i<=R;i++)
    {
        for(int j=1;j<=C;j++)
        {
            bool isa=true;
            //不接国王
            int temp=0;
            for(int k=0;k<PoS.size();k++)//加上每个骑士走到这点所需的距离
            {
                if(step[i][j][PoS[k].first][PoS[k].second]==2139062143)
                    isa=false;
                temp+=step[i][j][PoS[k].first][PoS[k].second];
            }
            temp+=kingstep[i][j];
            if(!isa)
                break;
            int temp2=MofInt;
            //接上国王

            int other;
            int spetialone;
            for(int k=0;k<PoS.size();k++)//枚举哪个骑士接国王
            {
                other=temp-step[i][j][PoS[k].first][PoS[k].second]-kingstep[i][j];;
                //在哪接

                for(int l=max(1,king.first-2);l<=min(R,king.first+2);l++)
                {
                    for(int p=max(1,king.second-2);p<=min(C,king.second+2);p++)
                    {
                        if(kingstep[l][p]==2139062143||step[i][j][l][p]==2139062143||step[l][p][PoS[k].first][PoS[k].second]==2139062143)
                            break;
                        spetialone=step[i][j][l][p]+step[l][p][PoS[k].first][PoS[k].second]+kingstep[l][p];
                        temp2=min(temp2,spetialone+other);
                    }
                }
            }
            temp=min(temp,temp2);
            ans=min(ans,temp);//和国王直接走到集合点作比较
        }
    }
    if(ans==MofInt&&PoS.size()==1)//如果骑士寸步难行,且只有一个骑士
    {
        ans=kingstep[PoS[0].first][PoS[0].second];
    }
    cout<<ans<<endl;
}
int main()
{
    freopen("camelot.in","r",stdin);
    freopen("camelot.out","w",stdout);
    scanf("%d%d",&C,&R);
    int b;char a;
    PoS.clear();
    getchar();
    scanf("%c %d",&a,&b);
    king.first=a-‘A‘+1;king.second=b;
    getchar();
    while(~scanf("%c %d",&a,&b))
    {
        PoS.push_back(position(a-‘A‘+1,b));
        getchar();
    }
    BFSforking();
    BFS();
    output();
    return 0;
}

  

时间: 2024-10-19 16:02:02

usaco Camelot的相关文章

USACO camelot 好题

这道题的意思是地图上有一些骑士和一个国王, 骑士和国王要在一点会和,你可以选择一个骑士和国王在一点会和然后骑士会带着国王继续走, 问他们汇合的最少步数和是多少?考虑一个骑士当没有国王的时候可以很容易的求出他到每个点的最短路径a, 现在他要带着国王, 那么我们可以计算出他带着国王到某一点的最短路径b, 那么为了接国王他多走的路就是b - a,这下我们可以维护两个数组, cost[i][j]表示所有骑士不接国王到达i, j所需要的最短的步数, kcost[i][j]表示有一个骑士接国王到i,j,骑士

[USACO3.3.3]camelot

题目传送门:http://www.nocow.cn/index.php/Translate:USACO/camelot 这道题让我心痛,一开始写写不出,后来拖了很久,决定去看题解,没想到又看不懂官方题解,唉!后来看了下面的题解做了出来.题解的话,大概就是先预处理每个格子到另外格子的位置,再枚举在王的坐标+-2位置接王,枚举所有棋子的集中点加起来计算就好了.我的代码为了方便略粗鲁. 题解传送门:http://www.nocow.cn/index.php/USACO/camelot /* ID:ab

USACO 3.3 Camelot

CamelotIOI 98 Centuries ago, King Arthur and the Knights of the Round Table used to meet every year on New Year's Day to celebrate their fellowship. In remembrance of these events, we consider a board game for one player, on which one chesspiece king

洛谷P1930 亚瑟王的宫殿 Camelot

P1930 亚瑟王的宫殿 Camelot 19通过 53提交 题目提供者JOHNKRAM 标签USACO 难度提高+/省选- 提交  讨论  题解 最新讨论 暂时没有讨论 题目描述 很久以前,亚瑟王和他的骑士习惯每年元旦去庆祝他们的友谊.为了纪念上述事件, 我们把这些故事看作是一个棋盘游戏.有一个国王和若干个骑士被放置在一个由许多方格 组成的棋盘上,没有两个骑士在同一个方格内. 这个例子是标准的 8*8 棋盘 国王可以移动到任何一个相邻的方格,从下图中黑子位置到下图中白子位置前提是他 不掉出棋盘

USACO Section 3.3 Camlot

BFS.先算出棋盘上每个点到各个点knight需要的步数:然后枚举所有点,其中再枚举king是自己到的还是knight带它去的(假如是knight带它的,枚举king周围的2格(网上都这么说,似乎是个结论?还是usaco数据太弱了?不过看跑出来的时间,全部枚举或许也可以)).一开始觉得挺麻烦的,不过只要思路清晰写起来应该也没多大问题.大概就是这样了. #include<cstdio> #include<iostream> #include<algorithm> #inc

COGS 696. [IOI1996][USACO 2.3] 最长前缀

★   输入文件:prefix.in   输出文件:prefix.out   简单对比时间限制:1 s   内存限制:128 MB 描述 USACO 2.3.1 IOI96 在生物学中,一些生物的结构是用包含其要素的大写字母序列来表示的.生物学家对于把长的序列分解成较短的序列(即元素)很感兴趣. 如果一个集合 P 中的元素可以通过串联(元素可以重复使用,相当于 Pascal 中的 “+” 运算符)组成一个序列 S ,那么我们认为序列 S 可以分解为 P 中的元素.元素不一定要全部出现(如下例中B

USACO prefix TrieTree + DP

/* ID:kevin_s1 PROG:prefix LANG:C++ */ #include <iostream> #include <cstdio> #include <string> #include <cstring> #include <vector> #include <map> #include <set> #include <algorithm> #include <cstdlib>

【USACO 1.3.4】牛式

[題目描述 ] 下面是一个乘法竖式,如果用我们给定的那n个数字来取代*,可以使式子成立的话,我们就叫这个式子牛式. * * * x * * ---------- * * * * * * ---------- * * * * 数字只能取代*,当然第一位不能为0,况且给定的数字里不包括0. 注意一下在美国的学校中教的"部分乘积",第一部分乘积是第二个数的个位和第一个数的积,第二部分乘积是第二个数的十位和第一个数的乘积. 写一个程序找出所有的牛式. [格式] INPUT FORMAT: (f

USACO Chapter 1 Section 1.1

USACO的题解和翻译已经很多了... 我只是把自己刷的代码保存一下. 1.PROB Your Ride Is Here 1 /* 2 ID:xiekeyi1 3 PROG:ride 4 LANG:C++ 5 */ 6 7 #include<bits/stdc++.h> 8 using namespace std ; 9 10 int main() 11 { 12 freopen("ride.in","r",stdin); 13 freopen(&quo