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 }

 

  

posted @ 2015-01-30 17:05  Naturain  阅读(239)  评论(0编辑  收藏  举报