POJ1699 HDU 1560 Best Sequence(AC自动机 最短路)

时间:2021-10-13 16:23:34

曾写过迭代加深搜索的方法,现在使用在AC自动上跑最短路的方法

dp[i][j]表示状态为到节点i,模式串是否包含的状态为j的最短串的长度,则状态转移方程为:

dp[nx][ny] = min(dp[x][y] + 1) , 其中nx为x后继结点,ny为从y转移过来的新状态,更新时加入队列

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
#include<set>
#include<string>
using namespace std; int Hash[128];
typedef long long LL; const int N = 150, CH = 4, INF = 0x3F3F3F3F;
int n, cnt;
struct Trie{
Trie *next[CH];
Trie *fail;
int id;
}tree[N], *q[50000]; int chi[N][CH];
int sum[N];
int dp[N][1024];
bool inq[N][1024]; class ACauto{
private:
int nxt;
Trie *root; public:
ACauto(){
root = &tree[0];
nxt=0;
memset(&tree[0], 0, sizeof(Trie));
} void insert(string s, int id){
Trie *p = root;
for(int i = 0; i < s.size(); i++){
int c = Hash[s[i]];
if(!p -> next[c]){
memset(&tree[++nxt], 0, sizeof(Trie));
p -> next[c] = &tree[nxt];
p -> next[c] -> id = nxt;
}
p = p -> next[c];
}
sum[p->id] = 1 <<id;
} void build(){
int front = 0, rear = 0;
q[rear++] = root;
root -> fail = NULL;
while(front < rear){
Trie *cur = q[front++]; if(cur -> fail){
sum[cur->id] |= sum[cur->fail ->id];
} for(int i = 0; i < CH; i++){ Trie *son = cur -> next[i];
Trie *tp = (cur == root)? root: cur -> fail->next[i];
if(son == NULL){
cur -> next[i] = tp;
}else{
son -> fail = tp;
q[rear++] = son;
}
son = cur -> next[i];
chi[cur->id][i] = son->id;
}
}
} void solve(){
memset(dp, 0x3F, sizeof(dp));
memset(inq, 0, sizeof(inq));
queue<int> q;
dp[0][0] = 0;
inq[0][0] = 1;
int st = 1 << cnt;
q.push(0);
while(!q.empty()){
int u = q.front();
q.pop();
int x = u / st;
int y = u % st;
inq[x][y] = 0;
for(int i = 0 ; i < CH; i++){
int nx = chi[x][i], ny = y | sum[chi[x][i]];
if(dp[nx][ny] > dp[x][y] + 1){
dp[nx][ny] = dp[x][y] + 1;
if(!inq[nx][ny]){
q.push(nx * st + ny);
inq[nx][ny] = 1;
}
}
}
}
int ans = INF;
for(int i = 0; i <= nxt; i++){
ans = min(ans, dp[i][st - 1]);
}
printf("%d\n", ans); } }; char str[100];
int main(){
Hash['A'] = 0;
Hash['C'] = 1;
Hash['G'] = 2;
Hash['T'] = 3;
int t;
cin>>t;
while(t--){
int n;
cin>>n;
set<string> st;
for(int i = 0; i < n; i++){
string str;
cin>>str;
st.insert(str);
}
ACauto ac;
memset(sum, 0, sizeof(sum)); cnt = 0;
for(set<string>::iterator it = st.begin(); it != st.end(); it++){
ac.insert(*it, cnt++);
}
ac.build();
ac.solve();
} return 0;
}