poj1618

题意:有n个长度为len的模式串,问在所有长度为L的串中有多少个串符合如下条件:该串所有长度为len的子串都在这n个模式串中。

分析:动态规划,f[i][j]表示长度为i的以第j个模式串为后缀的符合条件的串有多少个,f[i + 1][k] += f[i][j];

k要符合第k个模式串可以由第j个模式串去掉首字母,再在结尾添加一个字母得到。就相当于我们不断的将模式串有重叠地(重叠长度为len-1)搭在当前构成的长度为i的串的结尾,使长度变为i+1。

也就是第k个模式串就是长度为i+1的串比长度为i的串多出的那个长度为len的子串(长度为i+1的串的长度为len的子串个数只比长度为i的串的长度为len的子串个数多1)。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;

#define maxn 605
#define maxl 30
#define maxm 105

struct Edge
{
    int next, v;
}edge[maxn * maxn];

int head[maxn];
int comb_cnt, type_cnt, streamer_len;
int comb_len;
char comb[maxn][maxl];
int ecount;
int f[maxm][maxn];

void input()
{
    for (int i = 0; i < comb_cnt; i++)
        scanf("%s", comb[i]);
}

void addedge(int a, int b)
{
    edge[ecount].v = b;
    edge[ecount].next = head[a];
    head[a] = ecount++;
}

bool connect1(char *a, char *b)
{
    for (int i = 1; i < comb_len; i++)
        if (a[i] != b[i - 1])
            return false;
    return true;
}

void make()
{
    comb_len = strlen(comb[0]);
    ecount = 0;
    memset(head, -1, sizeof(head));
    for (int i = 0; i < comb_cnt; i++)
        for (int j = 0; j < comb_cnt; j++)
            if (connect1(comb[i], comb[j]))
                addedge(i, j);
}

void work()
{
    memset(f, 0, sizeof(f));
    for (int i = 0; i < comb_cnt; i++)
        f[comb_len][i] = 1;
    for (int i = comb_len; i < streamer_len; i++)
        for (int j = 0; j < comb_cnt; j++)
            for (int k = head[j]; k != -1; k = edge[k].next)
                f[i + 1][edge[k].v] += f[i][j];
    int ans = 0;
    for (int i = 0; i < comb_cnt; i++)
        ans += f[streamer_len][i];
    printf("%d\n", ans);
}

int main()
{
    while (scanf("%d%d%d", &type_cnt, &streamer_len, &comb_cnt), type_cnt | streamer_len | comb_cnt)
    {
        input();
        make();
        work();
    }
    return 0;
}
View Code

 

posted @ 2013-06-02 17:00  金海峰  阅读(207)  评论(0编辑  收藏  举报