HDU 4511 小明系列故事——女友的考验 (AC自动机 + DP)题解
题意:从 1 走到 n,要求所走路径不能出现给定的路径,求最短路
思路:因为要求不能出现给定路径,那么我可以求助ac自动机完成判断。
我们可以在build的时候标记哪些路径不能出现,显然下面这种表示后缀不能出现,那么他也不能出现
if(node[node[u].fail].cnt && u) node[u].cnt = 1; //都不能取
然后再把图建完整。因为如果一个路径不在Trie中有两种情况,一种是他可能是某个不能走的串的前缀,那么我就重新指向这个不能走的串,比如Trie中只有AT,那么我走ATA相当于走AT再走回A;另一种是这个路径根本没出现过,那么相当于从0开始走。
if(!node[u].next[i]){ if(u == 0) node[u].next[i] = 0; else node[u].next[i] = node[node[u].fail].next[i]; }
dp[i][j]表示走到i点在AC自动机上走到j点的最小路径。
代码:
#include<cmath> #include<set> #include<map> #include<queue> #include<cstdio> #include<vector> #include<cstring> #include <iostream> #include<algorithm> using namespace std; typedef long long ll; typedef unsigned long long ull; const int maxn = 500 + 5; const int M = 50 + 5; const ull seed = 131; const double INF = 1e20; const int MOD = 1000000007; double x[M], y[M]; int s[M]; double dp[M][maxn]; int m, n; double dis(int i, int j){ return sqrt((x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j])); } struct Aho{ struct state{ int next[M]; int fail, cnt; }node[maxn]; int size; queue<int> q; void init(){ size = 0; newtrie(); while(!q.empty()) q.pop(); } int newtrie(){ memset(node[size].next, 0, sizeof(node[size].next)); node[size].cnt = node[size].fail = 0; return size++; } void insert(int s[], int len){ int now = 0; for(int i = 0; i < len; i++){ int c = s[i]; if(node[now].next[c] == 0){ node[now].next[c] = newtrie(); } now = node[now].next[c]; } node[now].cnt = 1; } void build(){ node[0].fail = -1; q.push(0); while(!q.empty()){ int u = q.front(); q.pop(); if(node[node[u].fail].cnt && u) node[u].cnt = 1; //都不能取 for(int i = 0; i <= n; i++){ if(!node[u].next[i]){ if(u == 0) node[u].next[i] = 0; else node[u].next[i] = node[node[u].fail].next[i]; } else{ if(u == 0) node[node[u].next[i]].fail = 0; else{ int v = node[u].fail; while(v != -1){ if(node[v].next[i]){ node[node[u].next[i]].fail = node[v].next[i]; break; } v = node[v].fail; } if(v == -1) node[node[u].next[i]].fail = 0; } q.push(node[u].next[i]); } } } } void query(){ for(int i = 0; i <= n; i++){ for(int j = 0; j < size; j++){ dp[i][j] = INF; } } dp[1][node[0].next[1]] = 0; for(int i = 1; i <= n; i++){ for(int j = 0; j < size; j++){ if(dp[i][j] == INF) continue; for(int k = i + 1; k <= n; k++){ if(node[node[j].next[k]].cnt) continue; dp[k][node[j].next[k]] = min(dp[k][node[j].next[k]], dp[i][j] + dis(i, k)); } } } double ans = INF; for(int i = 0; i < size; i++) if(dp[n][i] < INF) ans = min(ans, dp[n][i]); if(ans == INF) printf("Can not be reached!\n"); else printf("%.2f\n", ans); } }ac; int main(){ while(~scanf("%d%d", &n, &m) && n + m){ for(int i = 1; i <= n; i++){ scanf("%lf%lf", &x[i], &y[i]); } ac.init(); while(m--){ int k; scanf("%d", &k); for(int i = 0; i < k; i++){ scanf("%d", &s[i]); } ac.insert(s, k); } ac.build(); ac.query(); } return 0; }