题目大意:
给你一个字符串,表示拥有的字符为长度L,即操作的种类L ,然后给你一个无向图,有n个顶点,标号从1~n,之后输入一个S,表示起点,即你一开始所在的位置,然后给你一个集合Σ,先输入元素个数,然后输入包含的元素有哪些。然后再给你一个数N,表示操作的字符串长度。最后停留的点必须在Σ中。
之后输入一个n*L的矩阵,第i行第j列表示在点号为i的点上进行字符操作 j 将会到达的点,记为change[ i ][ j ]。
之后又是一个n*L的矩阵,第i行第j列表示在点号为i的点上进行字符操作 j 是否会消耗掉当前的字符 j ,如果是0,表示会消耗,跳到下一个字符,如果是1,表示不会消耗字符,在下一个点继续进行操作j。记为cost[ i ][ j ]
然后就是要得出有多少种操作字符串。
解题思路:
首先预处理。
首先对于点i的字符操作 j ,如果cost[ i ][ j ]=0,表示直接消耗掉,我们先不管。如果cost[ i ][ j ]=1,那么就需要查找到最后到消耗掉这个字符会到达哪里。但是有可能会出现最后无法消耗掉,那么我们就打一个标记,说明不能在 i 点进行 j 操作。
然后直接DP,f[ i ][ j ]表示消耗i个字母最后在点 j 停留的种类。
如果 j 可以 进行 p 操作,那么
f[ i+1 ][ change[ j ][ p ] ]+=f[i][j] (p=1->L)
最后输出所有 的f[ N ][ Σ[i] ]
要写高精度!!!!
AC代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
#define MAX(a,b) ((a)>(b)?(a):(b))
using namespace std;
int len;//字符数
int U;//点数
int S;//起点
int xigema[1010]={0};
int sx=0;//Σ的包含数
int n;//答案的长度
struct bian_
{
int change;
int cost;
}bian[10010][30]={{{0,0}}};
int f[70][1010][50]={{{0}}};
int hash[1010]={0};
int Times=0;
void Add(int p,int q,int pp,int qq)
{
f[p][q][0]=MAX(f[p][q][0],f[pp][qq][0]);
for(int i=1;i<=f[p][q][0];i++)
{
f[p][q][i]+=f[pp][qq][i];
f[p][q][i+1]+=f[p][q][i]/10000;
f[p][q][i]%=10000;
}
for(int i=f[p][q][0];f[p][q][i+1]>0;i++,f[p][q][0]++)
{
f[p][q][i+1]+=f[p][q][i]/10000;
f[p][q][i]%=10000;
}
return;
}
int dfs(int k,int p)
{
if(k==-1 || hash[k]==Times)
return -1;
hash[k]=Times;
if(bian[k][p].cost==0)
return bian[k][p].change;
else return dfs(bian[k][p].change,p);
}
int main()
{
char ch[10010]="\0";
gets(ch);
len=strlen(ch);
for(;ch[len-1]=='\n' || ch[len-1]=='\r';ch[--len]='\0');
scanf("%d",&U);
scanf("%d",&S);
scanf("%d",&sx);
for(int i=1;i<=sx;i++)
{
int j;
scanf("%d",&j);
xigema[j]=1;
}
for(int i=1;i<=U;i++)
for(int j=1;j<=len;j++)
scanf("%d",&bian[i][j].change);
for(int i=1;i<=U;i++)
for(int j=1;j<=len;j++)
scanf("%d",&bian[i][j].cost);
scanf("%d",&n);
for(int i=1;i<=U;i++)
for(int j=1;j<=len;j++)
if(bian[i][j].cost==1)
{
Times++;
bian[i][j].change=dfs(bian[i][j].change,j);
if(bian[i][j].change!=-1)
bian[i][j].cost=0;
}
f[0][S][0]=f[0][S][1]=1;
for(int i=0;i<n;i++)
for(int j=1;j<=U;j++)
for(int p=1;p<=len;p++)
if(bian[j][p].cost==0)
Add(i+1,bian[j][p].change,i,j);
for(int i=1;i<=U;i++)
if(xigema[i]==1)
Add(0,0,n,i);
printf("%d",f[0][0][f[0][0][0]]);
for(int i=f[0][0][0]-1;i>0;i--)
printf("%04d",f[0][0][i]);
return 0;
}