这是传说中的镇站神题么.. orz了
前前后后大概写了30k的代码,调了10+h才过...如果一开始就想清楚,只要调好2个typo,几个特判就好了,不用2个小时,所以写之前一定要想清楚细节...
首先用个四维数组保存任意点到任意点的距离,然后穷举集结点计算普通的骑士距离和,同时找出最短的先去载王再到集结点的距离。
一个优化是假设王自己的移动范围只有+-2.
同时要注意没有骑士和有骑士,但是格子数太小不能跳的情况。
代码如下:
#define TASK "camelot"
//#define SUBMIT
//#define LOCAL
#include <queue>
#include <algorithm>
#include <iostream>
using namespace std;
const int kx[] = {2,1,-1,-2,-2,-1,1,2};//knight jump
const int ky[] = {1,2,2,1,-1,-2,-2,-1};
const int maxn = 33;
const int inf = 1234567;
struct point {
int x, y, s;
point(int _x=0, int _y=0, int _s=0) {
x=_x, y=_y, s=_s;
}
};
point saber, k[maxn * maxn];
bool inline isValid(point& p);
void input();
void init();
int rr, cc; // rows , cols
int cnt = 0; // cnt of knights
int ta[maxn][maxn][maxn][maxn]; //table for precalculate dist
point get[maxn*maxn]; //point to get saber on
int nget = 0;
void bfs();
void solve();
int main()
{
#ifdef LOCAL
freopen(TASK ".in","r",stdin);
#endif
#ifdef SUBMIT
freopen(TASK ".out","w",stdout);
#endif
input();
init();
//special judge
if (0 == cnt) {
cout<<0<<endl;
}
else if (rr <3 && cc < 3) {
cout<<1<<endl;
}
else
{
bfs();
solve();
}
return 0;
}
void input() {
cin>>rr>>cc;
char a; int b;
cin>>a>>b;
saber.x = a - 'A' + 1; saber.y = b;
saber.s = 0;
k[0] = saber;
while(cin>>a>>b) {
k[++cnt].x = a - 'A' + 1;
k[cnt].y = b;
}
}
bool inline isValid(point& p) {
return p.x >0 && p.x <= cc && p.y>=1 && p.y<=rr;
}
void init() {
for (int i=1; i<=rr; i++) {
for (int j=1; j<=cc; j++) {
for (int k=1; k<=rr; k++) {
for (int l=1; l<=cc; l++)
{
ta[i][j][k][l] = inf;
}
}
}
}
int sax = max(1, saber.x-2);
int say = max(1, saber.y - 2);
int tax = min(cc, saber.x+2);
int tay = min(rr, saber.y + 2);
for (int i=sax; i<=tax; i++) {
for (int j=say; j<=tay; j++) {
get[++nget] = point(i, j);
}
}
}
void solve() {
int ret = inf, xpick, ypick, xga, yga;
xga = yga = xpick = ypick = -1; // for debug
for (int i=1; i<=nget; i++) {
int foo = max(abs(saber.y - get[i].y), abs(saber.x - get[i].x));
for (int sy=1; sy<=rr; sy++) {
for (int sx=1; sx<=cc; sx++) {
int ans = 0, bestfs = inf;
for (int id=1; id<=cnt; id++) {
ans += ta[k[id].y][k[id].x][sy][sx];
// calcucate the extra expense to get saber first and go to gather point than direct
int tmpfs = ta[k[id].y][k[id].x][get[i].y][get[i].x]
+ foo + ta[get[i].y][get[i].x][sy][sx]
- ta[k[id].y][k[id].x][sy][sx];
if (tmpfs < bestfs) {
bestfs = tmpfs;
xpick = get[i].x; ypick = get[i].y;
}
}
if (ans + bestfs < ret) {
ret = ans + bestfs;
xga = sx, yga = sy;
}
}
}
}
cout<<ret<<endl;
}
void bfs() {
for (int sy=1; sy<=rr; sy++) {
for (int sx=1; sx<=cc; sx++) {
ta[sy][sx][sy][sx] = 0;
point u = point(sx, sy); u.s=0;
queue<point> q;
q.push(u);
int vis[maxn][maxn]; memset(vis, 0, sizeof(vis));
vis[u.y][u.x] = 1;
while(q.size()) {
point cur = q.front(); q.pop();
for (int i=0; i<8; i++) {
point tmp;
tmp.y = cur.y + ky[i];
tmp.x = cur.x + kx[i];
tmp.s = cur.s + 1;
if (isValid(tmp) && vis[tmp.y][tmp.x] == 0) {
vis[tmp.y][tmp.x] = 1;
ta[sy][sx][tmp.y][tmp.x] = tmp.s;
q.push(tmp);
}
}
}
}
}
}
第十组数据usaco的机器居然比我的air跑得快1/3... 是机器升级了还是1.65G实在太渣..
Compiling...
Compile: OK
Executing...
Test 1: TEST OK [0.000 secs, 8036 KB]
Test 2: TEST OK [0.011 secs, 8168 KB]
Test 3: TEST OK [0.011 secs, 8168 KB]
Test 4: TEST OK [0.032 secs, 8168 KB]
Test 5: TEST OK [0.119 secs, 8168 KB]
Test 6: TEST OK [0.130 secs, 8168 KB]
Test 7: TEST OK [0.000 secs, 8168 KB]
Test 8: TEST OK [0.011 secs, 8168 KB]
Test 9: TEST OK [0.076 secs, 8168 KB]
Test 10: TEST OK [0.292 secs, 8168 KB]
Test 11: TEST OK [0.000 secs, 8168 KB]
Test 12: TEST OK [0.011 secs, 8168 KB]
Test 13: TEST OK [0.011 secs, 8168 KB]
Test 14: TEST OK [0.011 secs, 8168 KB]
Test 15: TEST OK [0.011 secs, 8168 KB]
Test 16: TEST OK [0.011 secs, 8168 KB]
Test 17: TEST OK [0.032 secs, 8168 KB]
Test 18: TEST OK [0.000 secs, 8036 KB]
Test 19: TEST OK [0.000 secs, 8168 KB]
Test 20: TEST OK [0.000 secs, 8168 KB]
All tests OK.
Your program ('camelot') produced all correct answers! This is your
submission #4 for this problem. Congratulations!