题目是这样的:
现在在数据库中保存有这样一张表(电影名:string,演员个数:number,演员名:string),如果演员A和演员B参加了同一部电影1的演播,演员B和演员C参加了另一个电影2的演播,而演员C和演员D参加了电影3的演出,那么,我们认为演员A和演员D之间存在友情联接,并定义这种联接的长度为3。请用C/C++/Java给出算法,找出所有演员的联接长度恰好为3的友情演员。
例如,有6部电影,信息如下:
1.《Mission Impossible 3》,演员3人,分别为:Tom Cruise,Maggie Q,Jeff Chase
2.《War Of The Worlds》,演员2人,分别为:Tom Cruise,Dakota Fanning
3.《Shark Tale》演员3人,分别为:Jack Black,Robert DeNiro,Will Smith
4.《Hide And Seek》,演员2人,分别为:Dakota Fanning,Robert DeNiro
5.《The Adventure Of Pluto Nash》,演员2人,分别为:Will Smith,Eddie Murphy
6.《Show Time》,演员2人,分别为:Robert DeNiro,Eddie Murphy
那么,请程序打印出这些演员的联接长度恰好为3的友情演员清单。
我使用的算法是双向广度优先搜索,先把所有的演员放在集合中,然后用两个for循环遍历,判断任意两个演员之间是否存在长度为3的连接,若存在,就打印出来。代码如下(使用标准C++和STL):
#include <map>
#include <set>
#include <functional>
#include <algorithm>
#include <iterator>
#include <functional>
#include <string>
#include <fstream>
#include <iostream>
using namespace std;
class CProblem
{
public:
void Print();
void Solve();
void GetFilm(string Actor,set<string>& FilmSet);
void GetLink1(string Actor,set<string>& ActorSet);
bool IsLink3(string actor1,string actor2);
CProblem(char* filename);
virtual ~CProblem();
protected:
multimap<string,string,less<string> >ActorFilmMap;
set<string>ActorSet;
};
CProblem::CProblem(char* filename)
{
ifstream fin(filename);
if(!fin)
{
cerr<<"File not open!"<<endl;
exit(1);
}
string ActorName,FilmName;
int ActorNum;
while(getline(fin,FilmName,'/n'))
{
fin>>ActorNum;
getline(fin,ActorName,'/n');
for(int i=0;i<ActorNum;i++)
{
getline(fin,ActorName,'/n');
ActorFilmMap.insert(make_pair(ActorName,FilmName));
ActorSet.insert(ActorName);
}
getline(fin,FilmName,'/n');
}
fin.close();
}
CProblem::~CProblem()
{
}
bool CProblem::IsLink3(string actor1, string actor2)
{
set<string>ActorSet1,ActorSet2;
GetLink1(actor1,ActorSet1);
GetLink1(actor2,ActorSet2);
set<string>::iterator Iter1,Iter2;
for(Iter1=ActorSet1.begin();Iter1!=ActorSet1.end();Iter1++)
for(Iter2=ActorSet2.begin();Iter2!=ActorSet2.end();Iter2++)
{
if(*Iter1!=*Iter2 && actor1!=*Iter2 && actor2!=*Iter1)
{
set<string,less<string> >FilmSet1,FilmSet2;
GetFilm(*Iter1,FilmSet1);
GetFilm(*Iter2,FilmSet2);
set<string>::iterator Iter3,Iter4;
for(Iter3=FilmSet1.begin();Iter3!=FilmSet1.end();Iter3++)
for(Iter4=FilmSet2.begin();Iter4!=FilmSet2.end();Iter4++)
if(*Iter3==*Iter4)
return true;
}
}
return false;
}
void CProblem::GetLink1(string Actor,set<string>& ActorSet)
{
set<string>FilmSet;
GetFilm(Actor,FilmSet);
set<string>::iterator Iter1;
multimap<string,string>::iterator Iter2;
for(Iter1=FilmSet.begin();Iter1!=FilmSet.end();Iter1++)
for(Iter2=ActorFilmMap.begin();Iter2!=ActorFilmMap.end();Iter2++)
{
if(*Iter1==Iter2->second && Actor!=Iter2->first)
ActorSet.insert(Iter2->first);
}
}
void CProblem::GetFilm(string Actor,set<string>& FilmSet)
{
multimap<string,string>::iterator Iter1;
for(Iter1=ActorFilmMap.lower_bound(Actor);Iter1!=ActorFilmMap.upper_bound(Actor);Iter1++)
{
FilmSet.insert(Iter1->second);
}
}
void CProblem::Solve()
{
set<string>::iterator Iter1,Iter2;
for(Iter1=ActorSet.begin();Iter1!=ActorSet.end();Iter1++)
{
for(Iter2=ActorSet.begin();Iter2!=ActorSet.end();Iter2++)
{
if(*Iter2==*Iter1)
continue;
if(IsLink3(*Iter1,*Iter2))
cout<<*Iter1<<" and "<<*Iter2<<" are of link 3."<<endl;
}
cout<<endl;
}
}
void CProblem::Print()
{
multimap<string,string>::iterator Iter1;
for(Iter1=ActorFilmMap.begin();Iter1!=ActorFilmMap.end();Iter1++)
cout<<Iter1->first<<" "<<Iter1->second<<endl;
}
int main()
{
CProblem prob("data.txt");
prob.Solve();
system("PAUSE");
return 0;
}
/
data.txt:
MissionImpossible3
3
TomCruise
MaggieQ
JeffChase
WarOfTheWorlds
2
TomCruise
DakotaFanning
SharkTale
3
JackBlack
RobertDeNiro
WillSmith
HideAndSeek
2
DakotaFanning
RobertDeNiro
TheAdventureOfPlutoNash
2
WillSmith
EddieMurphy
ShowTime
2
RobertDeNiro
EddieMurphy