Ural 1002(KMP,DP)
2015-01-30 16:49:47
思路:这种字典型的题很容易想到要用字典树...
其实这题的解法非常多,KMP+DP,字典树+DP,哈希+DP,AC自动机+DP。。基本就差在如何处理字符串。可见这道题目的强大之处----多解!
本弱采用KMP处理字符串。。(数据再BT一点就只能用AC自动机做了...)
1:先把所有输入的字符串处理成数字形式,然后和原串S匹配,找到每个匹配点,假设字符串a在原串S中的匹配终点为pos,即:a[i] = S[pos - alen + i] (1<=i<=alen)
对于每个匹配终点,建边:(pos - alen + 1) -> pos + 1,表示在考虑匹配时,点(pos-alen+1)可以通过匹配上字符串a从而转到pos+1,每条边还要记录字符串a编号这个信息,方便输出。
2:建好边后其实就是DAG了,然后就是经典的DAG上求最X路径问题了,本题求的是最短路。
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cmath> 5 #include <vector> 6 #include <map> 7 #include <set> 8 #include <stack> 9 #include <queue> 10 #include <string> 11 #include <iostream> 12 #include <algorithm> 13 using namespace std; 14 15 #define MEM(a,b) memset(a,b,sizeof(a)) 16 #define REP(i,n) for(int i=1;i<=(n);++i) 17 #define REV(i,n) for(int i=(n);i>=1;--i) 18 #define FOR(i,a,b) for(int i=(a);i<=(b);++i) 19 #define RFOR(i,a,b) for(int i=(a);i>=(b);--i) 20 #define MP(a,b) make_pair(a,b) 21 22 typedef long long ll; 23 typedef pair<int,int> pii; 24 const int INF = (1 << 30) - 1; 25 const int MAXN = 110; 26 const int MAXM = 10000000; 27 28 int s[MAXN]; 29 char word[50010][60]; 30 int first[MAXN],ecnt; 31 int w[50010][60]; 32 int n,P[MAXN],slen; 33 int dp[MAXN]; 34 int nxt[MAXN]; 35 36 struct edge{ 37 int v,wid,next; 38 }e[MAXM]; 39 40 int Choose(char c){ 41 if(c == 'i' || c == 'j') return 1; 42 if(c == 'a' || c == 'b' || c == 'c') return 2; 43 if(c == 'd' || c == 'e' || c == 'f') return 3; 44 if(c == 'g' || c == 'h') return 4; 45 if(c == 'k' || c == 'l') return 5; 46 if(c == 'm' || c == 'n') return 6; 47 if(c == 'p' || c == 'r' || c == 's') return 7; 48 if(c == 't' || c == 'u') return 8; 49 if(c == 'w' || c == 'x' || c == 'y') return 9; 50 if(c == 'o' || c == 'q' || c == 'z') return 0; 51 } 52 53 void Add_edge(int u,int v,int id){ 54 e[++ecnt].next = first[u]; 55 e[ecnt].v = v; 56 e[ecnt].wid = id; 57 first[u] = ecnt; 58 } 59 60 void Get_P(int p){ 61 MEM(P,0); 62 int j = 0; 63 FOR(i,2,w[p][0]){ 64 while(j > 0 && w[p][j + 1] != w[p][i]) j = P[j]; 65 if(w[p][j + 1] == w[p][i]) j++; 66 P[i] = j; 67 } 68 } 69 70 void KMP(int p){ 71 Get_P(p); 72 int j = 0; 73 FOR(i,1,slen){ 74 while(j > 0 && w[p][j + 1] != s[i]) j = P[j]; 75 if(w[p][j + 1] == s[i]) j++; 76 if(j == w[p][0]){ 77 Add_edge(i - w[p][0] + 1,i + 1,p); 78 j = P[j]; 79 } 80 } 81 } 82 83 int Solve(int p){ 84 if(dp[p] != -1) return dp[p]; 85 if(p > slen) return 0; 86 int res = INF; 87 for(int i = first[p]; ~i; i = e[i].next){ 88 int v = e[i].v; 89 int t = Solve(v); 90 if(t < res){ 91 res = t; 92 nxt[p] = i; 93 } 94 } 95 return dp[p] = res + 1; 96 } 97 98 void Print(int p){ 99 if(p > slen) return; 100 printf(" %s",word[e[nxt[p]].wid] + 1); 101 Print(e[nxt[p]].v); 102 } 103 104 int main(){ 105 char str[MAXN]; 106 while(scanf("%s",str + 1) != EOF){ 107 if(str[1] == '-' && str[2] == '1') break; 108 MEM(first,-1); 109 MEM(nxt,0); 110 MEM(dp,-1); 111 ecnt = 0; 112 slen = strlen(str + 1); 113 REP(i,slen) s[i] = str[i] - '0'; 114 scanf("%d",&n); 115 REP(i,n){ 116 scanf("%s",word[i] + 1); 117 int len = strlen(word[i] + 1); 118 w[i][0] = len; 119 REP(j,len) w[i][j] = Choose(word[i][j]); 120 KMP(i); 121 } 122 Solve(1); 123 if(dp[1] >= INF) printf("No solution.\n"); 124 else{ 125 printf("%s",word[e[nxt[1]].wid] + 1); 126 Print(e[nxt[1]].v); 127 puts(""); 128 } 129 } 130 return 0; 131 }