变形课(DFS+BFS)

题目

Problem Description

呃…变形课上Harry碰到了一点小麻烦,因为他并不像Hermione那样能够记住所有的咒语而随意的将一个棒球变成刺猬什么的,但是他发现了变形咒语的一个统一规律:如果咒语是以a开头b结尾的一个单词,那么它的作用就恰好是使A物体变成B物体.
Harry已经将他所会的所有咒语都列成了一个表,他想让你帮忙计算一下他是否能完成老师的作业,将一个B(ball)变成一个M(Mouse),你知道,如果他自己不能完成的话,他就只好向Hermione请教,并且被迫听一大堆好好学习的道理.

Input

测试数据有多组。每组有多行,每行一个单词,仅包括小写字母,是Harry所会的所有咒语.数字0表示一组输入结束.

Output

如果Harry可以完成他的作业,就输出"Yes.",否则就输出"No."(不要忽略了句号)

Sample Input

so soon river goes them got moon begin big 0

Sample Output

Yes.

思路

这道题目用DFS的思想做其实很好理解。
首先,既然每个单词只有首尾两个字符有用,我们只需要用字符数组存下两个字母就可以了。

string s;
char begi[1005],en[1005];//一些判题机上可能不可以用begin和end
while(cin>>s)
{
	n++;
	begi[n]=s[0];
	en[n]=s[s.length()-1];
}

接下来看题目,题目中说需要一些单词首尾相连形成由’b’到’m’的序列。打个生动形象 的比方,就是英文版的成语接龙。拿样例来说:big -> got -> them就可以了,那么我们只需要判断从首字母为’b’的单词找起能不能找到尾字母为’m’的单词就行了,所以可以打出一个原始版的DFS。

bool f;//f表示有没有找到
int n;//这...就是有几个单词
char begi[1005],en[1005];
void DFS(int k)
{
	if(f==1)
	return ;//找到了就不用找了
	if(en[k]=='m')
	{
		f=1;
		return ;
	}
	for(int i=1;i<=n;i++)
	{
		if(begi[i]==en[k])
		DFS(i);//反复寻找
	}
}

现在我们看这个原始的DFS能不能进行一些改进。我们会发现,用这个程序来找能不能找到是完全可以的,但是如果找不到的话,它就会一直进行反复横跳。比如输入"ba ab" ,程序就会ba -> ab -> ba -> ab…进入无限死循环。所以我们需要增加一个bool的vis数组来判断这个单词是否使用过(因为没有必要再用第二次)。如果使用过了就变成1,没有即为0。还有不要忘记找不到的话要重新把它变成0。

int n;
bool f,vis[1005];//标记是否用过
char begi[1005],en[1005];
void DFS(int k)
{
	if(f==1)
	return ;
	if(en[k]=='m')
	{
		f=1;
		return ;
	}
	for(int i=1;i<=n;i++)
	{
		if(vis[i]==0&&begi[i]==en[k])//还没用过
		{
			vis[i]=1;//现在用过了
			DFS(i);
			vis[i]=0;//用过了还是找不到,所以不要用
		}
	}
}

最后一个就是输入输出问题,一般来说这是最简单的问题,但是这道题目的输入输出还是很棘手的。一开始我企图用一个while(1)解决问题,但是谁知道while(cin)的功能太过强大导致^z都被当做字符读入了……所以还是想办法吧。显而易见,0表示一段单词,那么我们只需要将两个0中间的一段单词进行处理就可以了,同时,处理还可以在读入0的时候直接处理掉,非(hen)常(bu)方便。

int n;
bool f,vis[1005];
char begi[1005],en[1005];
string s;
while(cin>>s)
{
	if(s[0]=='0')//发现是0就处理一下
	{
		for(int i=1;i<=n;i++)
		vis[i]=0;//别忘了初始化   ps:memset的速度慢,不建议使用
		for(int i=1;i<=n;i++)
		{
			if(begi[i]=='b')//开头是b的就DFS一下
			{
				vis[i]=1;
				DFS(i);
			}
		}
		if(f==1)//找到了
		cout<<"Yes."<<endl;
		else//没找到
		cout<<"No."<<endl;
		n=0;f=0;//初始化*2
	}
	else//如果是单词就存进去
	{
		n++;
		begi[n]=s[0];
		en[n]=s[s.length()-1];
	}
}

好了,以上就是这道题目的做法详解。废话不多说了,上完整代码——

#include
//#include
using namespace std;
int n;
bool f,vis[1005];
char begi[1005],en[1005];
string s;
void DFS(int k)
{
	if(f==1)
	return ;
	if(en[k]=='m')
	{
		f=1;
		return ;
	}
	for(int i=1;i<=n;i++)
	{
		if(vis[i]==0&&begi[i]==en[k])
		{
			vis[i]=1;
			DFS(i);
			vis[i]=0;
		}
	}
}
int main()
{
	while(cin>>s)
	{
		if(s[0]=='0')
		{
			for(int i=1;i<=n;i++)
			vis[i]=0;
			for(int i=1;i<=n;i++)
			{
				if(begi[i]=='b')
				{
					vis[i]=1;
					DFS(i);
				}
			}
			if(f==1)
			cout<<"Yes."<<endl;
			else
			cout<<"No."<<endl;
			n=0;f=0;
		}
		else
		{
			n++;
			begi[n]=s[0];
			en[n]=s[s.length()-1];
		}
	}
	return 0;
}

另外,这里还附上BFS的代码,至于我为什么不写题解么……因为懒得不会 讲。
ps:这题其实BFS比DFS快很多,不过……DFS打起来方便嘛。

#include 
#include 
#include 
#include 
using namespace std;
int n;
struct node
{
	char from;
	char to;
	int visit;
}str[10000];
int main()
{
	int i=1;
	string s1;
	while(cin>>s1)
	{
		str[0].from=s1[0];
		str[0].to=s1[s1.size()-1];
		str[0].visit=0;
		while(i++)
		{
			cin>>s1;
			if(s1[0]=='0')
			break;
			str[i].from=s1[0];
			str[i].to=s1[s1.size()-1];
			str[i].visit=0;	
		}
		int n=i;
		int f=0;
		queue<char>s;
		s.push('b');		
		while(!s.empty())
		{
			char temp=s.front();
			s.pop();
			for(i=0;i<n;i++)
			{
				if(str[i].from==temp)
				{
					if(str[i].to=='m')
					{
						cout<<"Yes."<<endl;
						f=1;
						break;
					}
					if(str[i].visit==0)
					{	
						s.push(str[i].to);
						str[i].visit=1;
					}
				}
			}
			if(f)
			break;
		}
		if(!f)
		cout<<"No."<<endl;
		i=1;
	}
	return 0;  
}

你可能感兴趣的:(dfs,算法,c++,algorithm,bfs)