HDU 4511 AC自动机+DP

题意:

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4511
中文题。


思路:

常见的思路,不过要注意x和y要用double,否则溢出。


代码:

#include <bits/stdc++.h>
using namespace std;
const double INF = 1e20;
const int MAXN = 505;
const int K = 55;

int n, m, k;

struct ACauto {
    int next[MAXN][K], fail[MAXN], end[MAXN];
    int root, sz;

    int newnode() {
        for (int i = 1; i <= n; i++)
            next[sz][i] = -1;
        end[sz++] = 0;
        return sz - 1;
    }

    void init() {
        sz = 0;
        root = newnode();
    }

    void insert(int *buf, int len) {
        int now = root;
        for (int i = 0; i < len; i++) {
            int id = buf[i];
            if (next[now][id] == -1)
                next[now][id] = newnode();
            now = next[now][id];
        }
        end[now]++;
    }

    void build() {
        queue <int> Q;
        fail[root] = root;
        for (int i = 1; i <= n; i++) {
            if (next[root][i] == -1)
                next[root][i] = root;
            else {
                fail[next[root][i]] = root;
                Q.push(next[root][i]);
            }
        }
        while (!Q.empty()) {
            int now = Q.front(); Q.pop();
            end[now] += end[fail[now]];
            for (int i = 1; i <= n; i++) {
                if (next[now][i] == -1)
                    next[now][i] = next[fail[now]][i];
                else {
                    fail[next[now][i]] = next[fail[now]][i];
                    Q.push(next[now][i]);
                }
            }
        }
    }

    void show() {
        for (int i = 0; i < sz; i++) {
            for (int j = 1; j <= n; j++)
                printf("%d ", next[i][j]);
            printf("\n");
        }
    }

} ac;

double g[K][K], dp[K][MAXN];


void solve(int n) {
    for (int i = 1; i <= n; i++) {
        for (int j = 0; j < ac.sz; j++)
            dp[i][j] = INF;
    }
    dp[1][ac.next[ac.root][1]] = 0;
    for (int i = 1; i < n; i++) {
        for (int j = 0; j < ac.sz; j++) {
            if (ac.end[j] || dp[i][j] >= INF) continue;
            for (int ni = i + 1; ni <= n; ni++) {
                int nj = ac.next[j][ni];
                if (ac.end[nj]) continue;
                dp[ni][nj] = min(dp[ni][nj], dp[i][j] + g[i][ni]);
            }
        }
    }
    double ans = INF;
    for (int i = 0; i < ac.sz; i++) {
        ans = min(ans, dp[n][i]);
    }
    if (ans >= INF) puts("Can not be reached!");
    else printf("%.2f\n", ans);
}

int x[K], y[K], a[MAXN];

double dis(int x1, int y1, int x2, int y2) {
    double dx = (double)x1 - x2, dy = (double)y1 - y2;
    return sqrt(dx * dx + dy * dy);
}

int main() {
    //freopen("in.txt", "r", stdin);
    while (scanf("%d%d", &n, &m), n || m) {
        for (int i = 1; i <= n; i++) {
            scanf("%d%d", &x[i], &y[i]);
        }
        for (int i = 1; i <= n; i++) {
            for (int j = i + 1; j <= n; j++)
                g[i][j] = dis(x[i], y[i], x[j], y[j]);
        }
        ac.init();
        for (int i = 1; i <= m; i++) {
            scanf("%d", &k);
            for (int j = 0; j < k; j++) {
                scanf("%d", &a[j]);
            }
            ac.insert(a, k);
        }
        ac.build();
        //ac.show();
        solve(n);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值