AC自动机 + DP小结

HDU--2457 DNA repair

题意:给n个疾病的DNA序列和一个要修复的DNA序列,求最少换掉多少个字母,使得DNA序列不含疾病。不能修复输出-1.

dp[i][j]表示长度为以j节点结尾的串与给定串差异的最小值。

转移的时候,不能走病毒串的尾节点。

具体看代码。

//#pragma comment(linker,"/STACK:1024000000,1024000000")
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair PII;

#define pb push_back
#define MP make_pair
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1

const double eps = 1e-6;
const int inf = 0x3f3f3f3f;
const int mod = 100000;
const int maxn = 1100 + 10;


const int max_chd = 4;///字母表大小
struct AC_automata{
    int chd[maxn][max_chd], fail[maxn], cnt[maxn];///trie中的chd数组,fail指针,节点标记(是多少个串的结尾)
    int root, sz;///根节点,trie树大小
    int newnode(){///建立新的节点,返回节点编号
        for(int i=0; i Q;
        while(!Q.empty()) Q.pop();
        fail[root] = root;
        for(int i=0; i///当当前节点与给定串不同时,不同之数加1,否则不变
                    dp[i + 1][now] = min(dp[i + 1][now], tmp);///其实就是在构建不含尾节点的长度为n的串,求与原串的不同之处最少
                }
            }
        }
        int len = strlen(str);
        int ans = inf;
        for(int i=0; i


HDU -- 2296 Ring

题意:给m个字符串,每个字符串有一定的价值,求一个长度不超过n 的字符串,使得它的价值最大。

dp[i][j]表示长度不超过i,以节点j结尾的字符串的最大价值。在用一个字符串数组维护这个字符串即可。

//#pragma comment(linker,"/STACK:1024000000,1024000000")
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair PII;

#define pb push_back
#define MP make_pair
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1

const double eps = 1e-6;
const int inf = 0x3f3f3f3f;
const int mod = 100000;
const int maxn = 1100 + 10;


const int max_chd = 26;///字母表大小
struct AC_automata{
    int chd[maxn][max_chd], fail[maxn], cnt[maxn];///trie中的chd数组,fail指针,节点标记(是多少个串的结尾)
    int root, sz;///根节点,trie树大小
    int newnode(){///建立新的节点,返回节点编号
        for(int i=0; i Q;
        while(!Q.empty()) Q.pop();
        fail[root] = root;
        for(int i=0; i= 0){
                strcpy(tmp, ss[i][j]);
                int len = strlen(tmp);
                for(int k=0; k mx || (kk == mx && ok(tmp, ans))){
                            mx = kk;
                            strcpy(ans, tmp);
                        }
                    }
                }
            }
        }
        printf("%s\n", ans);
    }
}AC;

int m, n, T, v;
char str[111][20];
int main(){
    scanf("%d", &T);
    while(T--){
        scanf("%d%d", &n, &m);
        AC.init();
        for(int i=1; i<=m; i++)
            scanf("%s", str[i]);
        for(int i=1; i<=m; i++){
            scanf("%d", &v);
            AC.Insert(str[i], v);
        }
        AC.build();
        AC.solve(n);
    }
    return 0;
}



HDU -- 2825 Wireless Password

题意:给m个字符串,要求长度为n的至少包含k个给定字符串的个数。

dp[i][j][k]表示长度为i,以j节点结尾,包含给定字符串的状态为k的个数。(这题非常容易T。。。QAQ

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

typedef double DB;
typedef long long ll;
typedef unsigned long long ull;
typedef pair PII;

#define pb push_back
#define MP make_pair
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1

const DB eps = 1e-6;
const int inf = 0x3f3f3f3f;
const int mod = 20090717;
const int maxn = 100 + 10;

int n, m, k, dp[30][maxn][1 << 11];
char str[maxn];
int judge[1 << 11];
const int max_chd = 26;
struct AC_automata{
    int chd[maxn][max_chd], fail[maxn], cnt[maxn];
    int root, sz;
    int newnode(){
        for(int i=0; i Q;
        while(!Q.empty()) Q.pop();
        fail[root] = root;
        for(int i=0; i 0){
                    for(int ch=0; ch= k){
            for(int j=0; j>= 1;
        }
    }
    while(scanf("%d%d%d", &n, &m, &k) == 3){
        if(!n && !m && !k) break;
        AC.init();
        for(int i=0; i


HDU -- 3341 Lost's revenge

题意:给n的DNA序列和一个待修改的DNA序列,求这的DNA序列通过调换位置能最多包含多少个给定的DNA序列(包含多次重复计算)

丧病的题。。。大家还是去看kuangbin大神的题解http://www.cnblogs.com/kuangbin/p/3163648.html我也是照着敲的=。=

//#pragma comment(linker,"/STACK:1024000000,1024000000")
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

typedef double DB;
typedef long long ll;
typedef unsigned long long ull;
typedef pair PII;

#define pb push_back
#define MP make_pair
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1

const double eps = 1e-6;
const int inf = 0x3f3f3f3f;
const int mod = 100000;
const int maxn = 1000 + 10;

int n, cas = 0;
char str[maxn];

const int max_chd = 4;///字母表大小
struct AC_automata{
    int chd[maxn][max_chd], fail[maxn], cnt[maxn];///trie中的chd数组,fail指针,节点标记(是多少个串的结尾)
    int root, sz;///根节点,trie树大小
    int newnode(){///建立新的节点,返回节点编号
        for(int i=0; i Q;
        while(!Q.empty()) Q.pop();
        fail[root] = root;
        for(int i=0; i= 0){
                for(int j=0; j<4; j++){
                    if(j == 0 && A == num[0]) continue;
                    if(j == 1 && T == num[1]) continue;
                    if(j == 2 && G == num[2]) continue;
                    if(j == 3 && C == num[3]) continue;
                    dp[chd[i][j]][cur + bit[j]] = max(dp[chd[i][j]][cur + bit[j]], dp[i][cur] + cnt[chd[i][j]]);
                }
            }
        }
        int cur = bit[0] * num[0] + bit[1] * num[1] + bit[2] * num[2] + bit[3] * num[3];
        int ans = -1;
        for(int i=0; i


HDU -- 3247 Resource Archiver

题意:给n的资源串和m个病毒串。求一个串,使它包含所有的资源串而不包含病毒串,求这个串的最小长度。

首先把病毒串和资源串做上不同的标记放到AC自动机中。BFS求出资源串尾节点之间的距离。

然后dp[i][j]表示资源串的状态为i,以j资源串结尾的最小长度。

//#pragma comment(linker,"/STACK:1024000000,1024000000")
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

typedef double DB;
typedef long long ll;
typedef unsigned long long ull;
typedef pair PII;

#define pb push_back
#define MP make_pair
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1

const double eps = 1e-6;
const int inf = 0x3f3f3f3f;
const int mod = 100000;
const int maxn = 1000000 + 10;

int n, m;
char str[maxn];

const int max_chd = 2;///字母表大小
struct AC_automata{
    int chd[maxn][max_chd], fail[maxn], cnt[maxn];///trie中的chd数组,fail指针,节点标记(是多少个串的结尾)
    int root, sz;///根节点,trie树大小
    int newnode(){///建立新的节点,返回节点编号
        for(int i=0; i Q;
        while(!Q.empty()) Q.pop();
        fail[root] = root;
        for(int i=0; i Q;
    void bfs(){
        sour[0] = 0; tot = 1;///trie树的根节点一定要访问
        memset(mat, -1, sizeof(mat));///mat[i][j] = 资源串i和资源串j结尾的最短路
        for(int i=0; i 0) sour[tot++] = i;
        for(int i=0; i= 0 && d[tmp] < 0){///不是病毒并且以前没走过就可以走
                        d[tmp] = d[now] + 1;
                        Q.push(tmp);
                    }
                }
            }
            for(int j=0; j 0){
                    dp[i | cnt[sour[k]]][k] = min(dp[i | cnt[sour[k]]][k], dp[i][j] + mat[j][k]);
                }
            }
        }
        int ans = inf;
        for(int i=0; i



你可能感兴趣的:(hdu,总结,AC自动机)