sgu-201 Non Absorbing DFA

 题目大意:

给你一个字符串,表示拥有的字符为长度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;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值