USACO 3.3.3 Camelot

这是传说中的镇站神题么.. 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!



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值