【搜索】【动规】电话号码

1:电话号码

源程序名            phone.???pas, c, cpp

可执行文件名        phone.exe

输入文件名          phone.in

输出文件名          phone.out

【问题描述】

       电话机上每一个数字下面都写了若干个英文字母。分布如下:

      1abc

      2def

      3ghi

      4jkl

      5mn

      6opq

      7rst

      8uvw

      9xyz

      现在给定一个单词表和一串数字密码,请你用单词表中的单词翻译这个密码。

【输入】

       第一行为一个正整数N表示单词表中单词的个数(N100);

       第二行为一个长度不超过100的数字串,表示密码;

       接下来的N行,每行一个长度不超过20的单词,表示单词表。

【输出】

    仅一行,表示翻译后的原文,如果密码无法翻译,则输出“No Solutions!”,如果密码有多种翻译方式,则输出任意一种即可。

【样例】

       phone.in                              phone.out

       8                                        thi shs b boo k

       73373711664

       thi

       shs

       this

       is

       b

       a

       boo

       k

 

我考试用的动规,我想复杂度比搜索低得多

 

然后对拍。。发现有错,结果突然醒悟过来,这个题是有比较程序的。。。我吃多了去写一个对拍。。。

 

搜索:

#include <cstdio>
#include <string>
#include <cstdlib>

long g[110];
char name[110][30];
char name0[110][30];
char phone[110];
long n;
const long map[] = {1,1,1,2,2,2,3,3,3,4,4,4,5,5,6,6,6,7,7,7,8,8,8,9,9,9};

long getint()
{
	long rs=0;char tmp;bool sgn=1;
	do tmp = getchar();
	while (!isdigit(tmp)&&tmp-'-');
	if (tmp=='-'){sgn=0;tmp=getchar();}
	do rs=(rs<<3)+(rs<<1)+tmp-'0';
	while (isdigit(tmp=getchar()));
	return sgn?rs:-rs;
}
void output(long l)
{
	if (g[l])
	{
		printf("%s ",name0[g[l]]+1);
		output(l + name[g[l]][0]);
	}	
}
void dfs(long l)
{
	for (long i=1;i<n+1;i++)
	{
		if (l + name[i][0] > phone[0] + 1)
			continue;
		bool sgn = true;
		for (long j=0;j<name[i][0];j++)
			if (name[i][j+1]!=phone[l+j])
			{
				sgn = false;
				break;
			}
		if (!sgn) continue;
		if (l + name[i][0] == phone[0]+1)
		{
			g[l] = i;
			output(1);
			exit(0);
		}
		else
		{
			g[l] = i;
			dfs(l + name[i][0]);
		}
	}
}
int main()
{
	freopen("phone.in","r",stdin);
	freopen("std.out","w",stdout);
	n = getint();
	scanf("%s",phone+1);
	while (phone[++phone[0]]){phone[phone[0]]-='0';}
	phone[phone[0]--] = -1;
	for (long i=1;i<n+1;i++)
	{
		scanf("%s",name[i]+1);
		while(name[i][++name[i][0]])
		{
			name0[i][name[i][0]] = name[i][name[i][0]];
			if (name[i][name[i][0]] > 'Z')
				name[i][name[i][0]] = map[name[i][name[i][0]]-'a'];
			else
				name[i][name[i][0]] = map[name[i][name[i][0]]-'A'];
		}
		name[i][0] --;
	}
	dfs(1);
	printf("No Solutions!");
	return 0;
}


 

 

动规:

一开始忘了匹配。。。

while (word[i][++word[i][0]])一开始写成了while (word[i][word[i][0]++]),而且还忘了word[i][0]--。

没有写if (i-word[j][0]<0) continue;造成了死循环。

ouput(l-word[g[l]][0] 写成了 output(l-g[l][0]);

#include <cstdio>
#include <string>
const long map[] = {1,1,1,2,2,2,3,3,3,4,4,4,5,5,6,6,6,7,7,7,8,8,8,9,9,9};
char phone[110];
char word[110][30];
char word0[110][30];
bool f[110];
long g[110];
long getint()
{
	long rs=0;char tmp;bool sgn=1;
	do tmp = getchar();
	while (!isdigit(tmp)&&tmp-'-');
	if (tmp=='-'){sgn=0;tmp=getchar();}
	do rs=(rs<<3)+(rs<<1)+tmp-'0';
	while (isdigit(tmp=getchar()));
	return sgn?rs:-rs;
}
void output(long l)
{
	if (l == 0)
	{
		return;
	}
	output(l - word[g[l]][0]);
	printf("%s ",word0[g[l]]+1);
}
int main()
{
	freopen("phone.in","r",stdin);
	freopen("phone.out","w",stdout);
	
	long n = getint();
	scanf("%s",phone+1);
	while (phone[++phone[0]]){phone[phone[0]]-='0';}
	phone[0]--;
	for (long i=1;i<n+1;i++)
	{
		scanf("%s",word[i]+1);
		while (word[i][++word[i][0]])
		{
			word0[i][word[i][0]] = word[i][word[i][0]];
			if (word[i][word[i][0]]>'Z')
				word[i][word[i][0]]=map[word[i][word[i][0]]-'a'];
			else
				word[i][word[i][0]]=map[word[i][word[i][0]]-'A'];
		}
		word[i][0] --;
	}
	f[0] = true;
	for (long i=1;i<phone[0]+1;i++)
	{
		for (long j=1;j<n+1;j++)
		{
			bool sgn = true;
			if (i-word[j][0]<0) continue;
			for (long k=0;k<word[j][0];k++)
			{
				if (word[j][word[j][0]-k] != phone[i-k])
				{
					sgn = false;
					break;
				}
			}
			if (sgn && f[i-word[j][0]])
			{
				f[i] = true;
				g[i] = j;
			}
		}
	}
	if (f[phone[0]])
	{
		output(phone[0]);
	}
	else
	{
		printf("No Solutions!");
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值