题意:升序的给出一本若干个单词,每个单词都可删除一个字母,添加一个字母或者改变一个字母,如果任意一个操作以后能变成另外一个字典中的单词,那么就连一条有向边,求最长的长度。
分析:DAG的最长路和最短路在算法竞赛入门里边原原本本有的,结果我现在忘记了,,真是太弱了。。方法就是,用map对应键值(以建图),然后删除操作和修改操作可以看做同一个操作,之后每个操作都是在相应的位置添加一个 '*' 就可以了。想说的有两点,一个是为什么删除和修改可以看做一个操作,其实删除这个操作根本就是多余的,因为一个单词比方说add要和ad匹配,不一定要add删除,而是可以ad添加一个d,所以说删除操作是多余的;第二点是添加操作时,要注意两头都是可以放 '*' 的。
建完图以后用求DAG的最长路的方法进行dp即可。
具体见代码:
1 #include <stdio.h> 2 #include <algorithm> 3 #include <string.h> 4 #include <string> 5 #include <map> 6 #include <vector> 7 #include <iostream> 8 using namespace std; 9 const int N = 25000+5; 10 11 string s[N]; 12 vector<int> G[N]; 13 map<string,int> M; 14 int dp[N]; 15 16 string change(string s,int pos) //删除操作和改变操作可以看做是一样的 17 { 18 string ans = ""; 19 for(int i=0;i<s.size();i++) 20 { 21 if(pos == i) ans += '*'; 22 else ans += s[i]; 23 } 24 return ans; 25 } 26 27 string add(string s,int pos) 28 { 29 string ans = ""; 30 for(int i=0;i<s.size();i++) 31 { 32 if(pos == i) ans += '*'; 33 ans += s[i]; 34 } 35 if(pos == s.size()) ans += '*'; 36 return ans; 37 } 38 39 int dfs(int x) //dfs求DAG的最长边 40 { 41 if(dp[x] != -1) return dp[x]; 42 int ans = 0; 43 for(int i=0;i<G[x].size();i++) 44 { 45 int v = G[x][i]; 46 ans = max(ans,dfs(v)); 47 } 48 return dp[x] = ans + 1; 49 } 50 51 int main() 52 { 53 int cnt = 0; 54 while(cin>>s[cnt++]); 55 56 for(int i=0;i<cnt;i++) 57 { 58 for(int j=0;j<s[i].size();j++) 59 { 60 string t = change(s[i],j); 61 if(M.count(t)) 62 { 63 G[M[t]].push_back(i); 64 } 65 M[t] = i; 66 } 67 68 for(int j=0;j<=s[i].size();j++) 69 { 70 string t = add(s[i],j); 71 if(M.count(t)) 72 { 73 G[M[t]].push_back(i); 74 } 75 M[t]=i; 76 } 77 } 78 79 memset(dp,-1,sizeof(dp)); 80 int ans = 0; 81 for(int i=0;i<cnt;i++) 82 { 83 ans = max(ans,dfs(i)); 84 } 85 86 printf("%d\n",ans); 87 return 0; 88 }