bzoj3205 [Apio2013]机器人

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3205

http://uoj.ac/problem/107

【题解】

我们发现这就是一棵斯坦纳树啊。。

令f[l,r,a,b]表示合并了(l,r),当前在(a,b)的最小推的次数。

预处理出来每个点朝每个方向推一下到哪里。(dfs,注意处理循环情况)

然后我们就可以套斯坦纳树板子了。

但是发现过不了。。因为spfa好像复杂度不对?

由于spfa边权都是1,所以我们用bfs来扩展。

我们把原有的节点按照f值排序,然后维护一个栈来存储原有的节点,用一个队列存储扩展的节点。

容易发现这两个里面都是单调的。每次比较头即可。

然后复杂度对了。。注意要基数排序(?)

然后基数排序数组要开大啊不然会RE...

大概100w?

bzoj怎么都能过系列。

# include <queue>
# include <cctype>
# include <stdio.h>
# include <string.h>
# include <algorithm>
// # include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int M = 503, N = 10, F = 6e5 + 3, FF = 1e6 + 10;
const int mod = 1e9+7;

# define RG register
# define ST static

int n, W, H; 
char mp[M][M];
int f[N][N][M][M];

struct pa {
    int x, y;
    pa() {}
    pa(int x, int y) : x(x), y(y) {}
    friend bool operator == (pa a, pa b) {
        return a.x==b.x && a.y==b.y;
    }
    friend bool operator != (pa a, pa b) {
        return !(a==b);
    }
};

int dfs_clock;
pa dp[M][M][4];
int v[M][M][4];
// 0: up, 1: right, 2: down, 3: left
const int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};

inline pa dfs(int x, int y, int face) {
    if(v[x][y][face] == dfs_clock) return pa(-1, -1);
    v[x][y][face] = dfs_clock;
    if(dp[x][y][face] != pa(0, 0)) return dp[x][y][face];
    int nface = face, nx = x, ny = y;
    if(mp[x][y] == 'A') nface = (nface+3)%4;
    if(mp[x][y] == 'C') nface = (nface+1)%4;
    nx += dx[nface], ny += dy[nface];
    if(nx<=0 || ny<=0 || nx>H || ny>W) return dp[x][y][face] = pa(x, y);
    if(mp[nx][ny] == 'x') return dp[x][y][face] = pa(x, y);
    return dp[x][y][face] = dfs(nx, ny, nface);
}


pa q[F], st[F];
bool vis[M][M];
int su[FF], va[F], vn=0, stn;

inline void spfa(int sti, int stj) {
    int head = 1, tail = 0;
    memset(su, 0, sizeof su); vn = 0;
    int mx = -1e9, mi = 1e9;
    for (int i=1; i<=H; ++i)
        for (int j=1; j<=W; ++j)
            if(f[sti][stj][i][j] != 1e9) {
                q[++tail] = pa(i, j);
                va[++vn] = f[sti][stj][i][j];
                su[va[vn]] ++;
                if(va[vn] > mx) mx = va[vn];
                if(va[vn] < mi) mi = va[vn];
                vis[i][j] = 1;
            }
    for (int i=mi; i<=mx; ++i) su[i] += su[i-1];    
    for (int i=1; i<=vn; ++i) st[su[va[i]]--] = q[i]; stn = vn;
    reverse(st+1, st+stn+1);
    head = 1, tail = 0;
    while(head <= tail || stn) {
        pa t;
        if(head > tail) {
            t = st[stn];
            --stn;    
        } else if(!stn) {
            t = q[head];
            ++head;
        } else {
            int ta = f[sti][stj][q[head].x][q[head].y], tb = f[sti][stj][st[stn].x][st[stn].y];
            if(ta < tb) t = q[head], ++head;
            else t = st[stn], --stn;
        }
        vis[t.x][t.y] = 0;
        for (int i=0; i<4; ++i) {
            int nx = dp[t.x][t.y][i].x, ny = dp[t.x][t.y][i].y;
            if(nx == -1) continue;
            if(f[sti][stj][t.x][t.y]+1 < f[sti][stj][nx][ny]) {
                f[sti][stj][nx][ny] = f[sti][stj][t.x][t.y]+1;
                if(!vis[nx][ny]) {
                    vis[nx][ny] = 1;
                    q[++tail] = pa(nx, ny);
                }
            }
        }
    }
}

inline void debug() {
    for (int sti=1; sti<=n; ++sti)
        for (int stj=sti; stj<=n; ++stj)
            for (int i=1; i<=H; ++i)
                for (int j=1; j<=W; ++j) printf("(%d, %d) (H,W: %d, %d) %d\n", sti, stj, i, j, f[sti][stj][i][j]);
//    system("pause");
}

int main() {
    scanf("%d%d%d", &n, &W, &H);
    for (int i=1; i<=H; ++i) scanf("%s", mp[i]+1);
    for (int i=1; i<=H; ++i)
        for (int j=1; j<=W; ++j)
            for (int face=0; face<4; ++face)
                if(mp[i][j] == 'x') dp[i][j][face] = pa(-1, -1);
                else dp[i][j][face] = pa(0, 0);
    for (int i=1; i<=H; ++i)
        for (int j=1; j<=W; ++j) 
            for (int face=0; face<4; ++face) {
                dfs_clock++;
                dp[i][j][face] = dfs(i, j, face);
            }
//    for (int i=1; i<=H; ++i)
//        for (int j=1; j<=W; ++j)
//            for (int face=0; face<4; ++face) 
//                printf("i=%d, j=%d, face=%d,  dp[i][j][face] = (%d, %d)\n", i, j, face, dp[i][j][face].x, dp[i][j][face].y);
    
    for (int sti=1; sti<=n; ++sti)
        for (int stj=sti; stj<=n; ++stj)
            for (int i=1; i<=H; ++i)
                for (int j=1; j<=W; ++j)
                    f[sti][stj][i][j] = 1e9;

    for (int i=1; i<=H; ++i)
        for (int j=1; j<=W; ++j)
            if(isdigit(mp[i][j])) {
                int t = mp[i][j] - '0';
                f[t][t][i][j] = 0;
            }
    
    for (int len=1; len<=n; ++len) 
        for (int sti=1; sti<=n-len+1; ++sti) {
            int stj = sti + len - 1;
            // (sti, stj)  status
            for (int i=1; i<=H; ++i)
                for (int j=1; j<=W; ++j) 
                    for (int st = sti; st < stj; ++st)
                        f[sti][stj][i][j] = min(f[sti][stj][i][j], f[sti][st][i][j] + f[st+1][stj][i][j]);
            spfa(sti, stj);
        }
//    debug();    
    
    int ans = 1e9;
    for (int i=1; i<=H; ++i)
        for (int j=1; j<=W; ++j)
            ans = min(ans, f[1][n][i][j]);
    printf("%d\n", ans == 1e9 ? -1 : ans);
    
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/galaxies/p/bzoj3205.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值