USACO 3.3 Camelot

Camelot
IOI 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 and several knight pieces are placed on squares, no two knights on the same square.

This example board is the standard 8x8 array of squares:

The King can move to any adjacent square from  to  as long as it does not fall off the board:

A Knight can jump from  to , as long as it does not fall off the board:

During the play, the player can place more than one piece in the same square. The board squares are assumed big enough so that a piece is never an obstacle for any other piece to move freely.

The player‘s goal is to move the pieces so as to gather them all in the same square - in the minimal number of moves. To achieve this, he must move the pieces as prescribed above. Additionally, whenever the king and one or more knights are placed in the same square, the player may choose to move the king and one of the knights together from that point on, as a single knight, up to the final gathering point. Moving the knight together with the king counts as a single move.

Write a program to compute the minimum number of moves the player must perform to produce the gathering. The pieces can gather on any square, of course.

PROGRAM NAME: camelot

INPUT FORMAT

Line 1: Two space-separated integers: R,C, the number of rows and columns on the board. There will be no more than 26 columns and no more than 30 rows.
Line 2..end: The input file contains a sequence of space-separated letter/digit pairs, 1 or more per line. The first pair represents the board position of the king; subsequent pairs represent positions of knights. There might be 0 knights or the knights might fill the board. Rows are numbered starting at 1; columns are specified as upper case characters starting with `A‘.

SAMPLE INPUT (file camelot.in)

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

The king is positioned at D4. There are four knights, positioned at A3, A8, H1, and H8.

OUTPUT FORMAT

A single line with the number of moves to aggregate the pieces.

SAMPLE OUTPUT (file camelot.out)

10

SAMPLE OUTPUT ELABORATION

They gather at B5. 
Knight 1: A3 - B5 (1 move) 
Knight 2: A8 - C7 - B5 (2 moves) 
Knight 3: H1 - G3 - F5 - D4 (picking up king) - B5 (4 moves) 
Knight 4: H8 - F7 - D6 - B5 (3 moves) 
1 + 2 + 4 + 3 = 10 moves.

————————————————————————

看着这道题第一眼觉得我见过,好像是枚举,然后n3挂得毫无疑问

嗯其实是最短路问题,网上说的枚举都是简化题面了,和华容道有点类似【华容道多加了一维方向做状态】,就是要多加一维带王或者不带王的状态做spfa

第一步处理王到棋盘的所有最短路

第二步处理某个骑士到棋盘各处的最短路的同时,加一维状态0/1记录骑士是否带王,使用堆优,每次更新0的时候顺带就更新1【也就是设某个点p,我们初始把所有最短路刷成inf后,第一次更新1就相当于王到p的最短路和骑士到p的最短路之和,也就是shortest_path_of_knight[p][0]+shortest_path_of_king[p]】

超级快,最慢不到0.3s

两行老泪……终于AC了……

  1 /*
  2 ID: ivorysi
  3 PROG: camelot
  4 LANG: C++
  5 */
  6 #include <iostream>
  7 #include <cstdio>
  8 #include <cstring>
  9 #include <algorithm>
 10 #include <queue>
 11 #include <set>
 12 #include <vector>
 13 #include <string.h>
 14 #define siji(i,x,y) for(int i=(x);i<=(y);++i)
 15 #define gongzi(j,x,y) for(int j=(x);j>=(y);--j)
 16 #define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)
 17 #define sigongzi(j,x,y) for(int j=(x);j>(y);--j)
 18 #define inf 0x3f3f3f3f
 19 #define MAXN 400005
 20 #define ivorysi
 21 #define mo 97797977
 22 #define ha 974711
 23 #define ba 47
 24 #define fi first
 25 #define se second
 26 #define pii pair<int,int>
 27 using namespace std;
 28 typedef long long ll;
 29 int sp[805][2];
 30 int knivis[805][2];
 31 int vis[35][35];
 32 int ksp[805];
 33 int kingcost[805];
 34 int r,c;
 35 int ky[8]={1,2,2,1,-1,-2,-2,-1};
 36 int kx[8]={2,1,-1,-2,-2,-1,1,2};
 37 int kj[8]={1,1,1,0,-1,-1,-1,0};
 38 int ki[8]={1,0,-1,-1,-1,0,1,1};
 39 struct node {
 40     int rr,cc,step;
 41 };
 42 queue<node> q;
 43 void pre1(int u) {
 44     memset(vis,0,sizeof(vis));
 45     int cx=(u-1)%c+1,rx=(u-1)/c+1;
 46     while(!q.empty()) q.pop();
 47     q.push((node){rx,cx,0});
 48     vis[rx][cx]=1;
 49     while(!q.empty()) {
 50         node nw=q.front();q.pop();
 51         kingcost[(nw.rr-1)*c+nw.cc]=ksp[(nw.rr-1)*c+nw.cc]=nw.step;
 52         siji(i,0,7) {
 53             int z=nw.rr+ki[i],w=nw.cc+kj[i];
 54             if(z<=r&&z>=1&&w<=c&&w>=1&& vis[z][w]==0) {
 55                 vis[z][w]=1;
 56                 q.push((node){z,w,nw.step+1});
 57             }
 58         }
 59     }
 60 }
 61 struct data{
 62     int rr,cc,cking,step;
 63     bool operator < (const data &rhs) const{
 64         return step>rhs.step;
 65     }
 66 };
 67 priority_queue<data> q1;
 68 void spfa(int u) {
 69     memset(sp,inf,sizeof(sp));
 70     memset(knivis,0,sizeof(vis));
 71     while(!q1.empty()) q1.pop();
 72     int cx=(u-1)%c+1,rx=(u-1)/c+1;
 73     q1.push((data){rx,cx,0,0});
 74     sp[u][0]=0;
 75     knivis[u][0]=1;
 76     while(!q1.empty()) {
 77         data nw=q1.top();q1.pop();
 78         siji(i,0,7) {
 79             int z=nw.rr+kx[i],w=nw.cc+ky[i];
 80             if(z<=r&&z>=1&&w<=c&&w>=1) {
 81                 if(sp[(z-1)*c+w][nw.cking]>nw.step+1) {
 82                     sp[(z-1)*c+w][nw.cking]=nw.step+1;
 83                     if(!knivis[(z-1)*c+w][nw.cking]){
 84                         knivis[(z-1)*c+w][nw.cking]=1;
 85                         q1.push((data){z,w,nw.cking,nw.step+1});
 86                     }
 87                 }
 88             }
 89         }
 90         if(nw.cking==0 && sp[(nw.rr-1)*c+nw.cc][1]>nw.step+ksp[(nw.rr-1)*c+nw.cc]) {
 91             sp[(nw.rr-1)*c+nw.cc][1]=nw.step+ksp[(nw.rr-1)*c+nw.cc];
 92             if(!knivis[(nw.rr-1)*c+nw.cc][1]){
 93                 knivis[(nw.rr-1)*c+nw.cc][1]=1;
 94                 q1.push((data){nw.rr,nw.cc,1,sp[(nw.rr-1)*c+nw.cc][1]});
 95             }
 96         }
 97         knivis[(nw.rr-1)*c+nw.cc][nw.cking]=0;
 98     }
 99
100 }
101 int king,kni[805],cnt;
102 int dist[805];
103 void init(){
104     scanf("%d%d",&r,&c);
105     char str[5];int b;
106     char s;
107     scanf("%s%d",str,&b);
108     siji(i,0,4) if(str[i] >=‘A‘&&str[i]<=‘Z‘) {s=str[i];break;}
109     king=(b-1)*c+s-‘A‘+1;
110     while(1){
111         scanf("%s %d",str,&b);
112         if(b==0) break;
113         siji(j,0,4) if(str[j] >=‘A‘&&str[j]<=‘Z‘) {s=str[j];break;}
114         kni[++cnt]=(b-1)*c+s-‘A‘+1;
115         b=0;
116     }
117     pre1(king);
118
119 }
120 void solve() {
121     init();
122     siji(i,1,cnt) {
123         spfa(kni[i]);
124         siji(j,1,r*c) {
125             if(sp[j][0]==inf||dist[j]==-1) {dist[j]=-1;continue;}
126             dist[j]+=sp[j][0];
127             kingcost[j]=min(kingcost[j],sp[j][1]-sp[j][0]);
128         }
129     }
130     int ans=inf;
131     siji(j,1,r*c) {
132         if(dist[j]==-1) continue;
133         ans=min(kingcost[j]+dist[j],ans);
134     }
135     printf("%d\n",ans);
136 }
137 int main(int argc, char const *argv[])
138 {
139 #ifdef ivorysi
140     freopen("camelot.in","r",stdin);
141     freopen("camelot.out","w",stdout);
142 #else
143     freopen("f1.in","r",stdin);
144 #endif
145     solve();
146 }
时间: 2024-10-11 04:39:24

USACO 3.3 Camelot的相关文章

usaco Camelot

题意是,国王和很多骑士在棋盘的不同位置,国王要和骑士在一点聚集. 若某个骑士和国王相遇之后,骑士和国王共同走一步,只算一步.等于是骑士背上了国王,国王不再走路. 第一遍我的算法用BFS计算出了每个骑士到棋盘上每个位置的最短距离.枚举每个点作为集合点,然后判断骑士能否在走到集合点的过程中遇上国王.依据是,国王所在点在骑士要到达的距离小于集合点,这么做其实并不能保证骑士遇见了国王,但还是骗过了5个测试点. 后来看别人才知道是国王在走两步只内就能遇见骑士.关于证明我没找到. /* ID: modeng

USACO camelot 好题

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

洛谷P1930 亚瑟王的宫殿 Camelot

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

[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 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