POJ 1699
2021/7/1 23:51:28
本文主要是介绍POJ 1699,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
算是一道水题,但是被折腾并不幸多次贡献WA...
太久不写代码略显生疏。思路其实是有的,大体分为两种
第一种是开始尝试的,但就是这里开始不停找不到出路,不明白是何方测评神仙数据卡着,discuss里的有问题的测试数据过的都没问题。思路如下:
- 之前一道题的练习,领悟到AC自动机本质上是构建了一个很特殊的图,我们寻找这样的字符串的过程,其实可以看做在这个图上旅行的过程,找到一个最短路径,遍历所有点,是的,就变成一个数量级较小的旅行商问题
- 问题在于重叠的定义,这道题是必须前缀和后缀连接的。所以每当发现当前节点是一个完整匹配串的节点的时候,需要不断利用fail指针回溯找到当前此状态所有可以被自动机完整接受的合法输入串。
- 这道题妙就妙在虽然是旅行商,但是可以利用状态压缩DP来做,或者状态压缩BFS,只是一直没能调出来,不知道那个神仙数据是什么
第二种其实是一开始方法实践之后想到的,其实方法一绕了远路,与其用AC自动机完整求出,不如直接构造两两输入字符串的“距离”矩阵:
- 所以思路很明显,先构造距离矩阵
- 虽然这道题数据量很小,但还是值得思考,寻找有没有快速方法
- 自己有想过KMP但没实现出来,简单看了下便恍然大悟,非常巧妙的思路,KMP匹配(s在前,t在后),将,s作为目标串,而t作为模式串,就这样一直匹配到s的最后,这是剩余的在t中用作索引的变量就记录了这个长度值,按照一般KMP匹配思路,其实这是一个边角料而已,所以灵活运用就体现在这。
- 寻路又用到巧妙的状压DP,定义dp(i, j)为在状态i,且最后一个串为j(顺序以输入为准)
#include <iostream> #include <algorithm> #include <queue> #include <string> #include <vector> #include <cstdio> #include <cstdlib> #include <cstring> #include <cassert> #include <cmath> #include <string> #include <stack> #include <map> #include <set> #include <deque> using namespace std; const int maxn= 15; const int maxl= 25; const int maxs= (1<<10)+5; const int INF= 0x3f3f3f3f; int n; char dna[maxn][maxl]; int bd[maxn][maxn], k_next[maxn][maxl]; int lth[maxn]; int dv[maxs][maxn]; void PreKMP(char *x, int m, int *kmp_next) { int i, j; i= 0; j= kmp_next[0]= -1; while (i< m){ while (j> -1 && x[i]!= x[j]){ j= kmp_next[j]; } if (x[++i]== x[++j]){ kmp_next[i]= kmp_next[j]; } else{ kmp_next[i]= j; } } } int CalcOver(int s, int t) { int i, j; i= j= 0; while (1){ while (j> -1 && dna[s][i]!= dna[t][j]){ j= k_next[t][j]; } ++i; ++j; if (i>= lth[s]){ break; } if (j>= lth[t]){ j= k_next[t][j]; } } return j; } int main(int argc, char const *argv[]) { int kase= 0; scanf("%d", &kase); while (kase--){ scanf("%d", &n); for (int i= 0; i< n; ++i){ scanf(" %s", dna[i]); lth[i]= strlen(dna[i]); PreKMP(dna[i], lth[i], k_next[i]); } for (int i= 0; i< n; ++i){ for (int j= 0; j< n; ++j){ if (i== j){ bd[i][j]= lth[i]; } else{ bd[i][j]= CalcOver(i, j); } } } const int e_mk= (1<<n)-1; for (int i= 0; i<= e_mk; ++i){ for (int j= 0; j< n; ++j){ dv[i][j]= INF; if (i & (1<<j)){ if (0== (i ^ (1<<j))){ dv[i][j]= lth[j]; } else{ int ii= i ^ (1<<j); for (int k= 0; k< n; ++k){ if (ii & (1<<k)){ dv[i][j]= min(dv[i][j], dv[ii][k]+lth[j]-bd[k][j]); } } } } } } int ans= INF; for (int i= 0; i< n; ++i){ ans= min(ans, dv[e_mk][i]); } printf("%d\n", ans); } return 0; }
这篇关于POJ 1699的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-09-28微服务架构中API版本控制的实践
- 2024-09-28AI给的和自己写的Python代码,都无法改变输入框的内容,替换也不行
- 2024-09-27Sentinel配置限流资料:新手入门教程
- 2024-09-27Sentinel配置限流资料详解
- 2024-09-27Sentinel限流资料:新手入门教程
- 2024-09-26Sentinel限流资料入门详解
- 2024-09-26Springboot框架资料:初学者入门教程
- 2024-09-26Springboot框架资料详解:新手入门教程
- 2024-09-26Springboot企业级开发资料:新手入门指南
- 2024-09-26SpringBoot企业级开发资料新手指南