Idiomatic Phrases Game(HDU 1546)

题目链接

题目描述

Tom is playing a game called Idiomatic Phrases Game. An idiom consists of several Chinese characters and has a certain meaning. This game will give Tom two idioms. He should build a list of idioms and the list starts and ends with the two given idioms. For every two adjacent idioms, the last Chinese character of the former idiom should be the same as the first character of the latter one. For each time, Tom has a dictionary that he must pick idioms from and each idiom in the dictionary has a value indicates how long Tom will take to find the next proper idiom in the final list. Now you are asked to write a program to compute the shortest time Tom will take by giving you the idiom dictionary.

输入格式

The input consists of several test cases. Each test case contains an idiom dictionary. The dictionary is started by an integer N (0 < N < 1000) in one line. The following is N lines. Each line contains an integer T (the time Tom will take to work out) and an idiom. One idiom consists of several Chinese characters (at least 3) and one Chinese character consists of four hex digit (i.e., 0 to 9 and A to F). Note that the first and last idioms in the dictionary are the source and target idioms in the game. The input ends up with a case that N = 0. Do not process this case.

输出格式

One line for each case. Output an integer indicating the shortest time Tome will take. If the list can not be built, please output -1.

输入样例

5
5 12345978ABCD2341
5 23415608ACBD3412
7 34125678AEFD4123
15 23415673ACC34123
4 41235673FBCD2156
2
20 12345678ABCD
30 DCBF5432167D
0

输出样例

17
-1

分析

本题只是建图很麻烦,求最短路套用模板就好。
建图的时候用set存储所有顶点,用vector动态数组存储相邻顶点,而用map存储成语首汉字所在动态数组下标,然后建图即可。

源程序

Dijkstra算法

#include <bits/stdc++.h>
#define MAXN 1005
using namespace std;
struct Edge{
	int v,w,next;
	Edge(){};
	Edge(int _v,int _w,int _next){
		v=_v,w=_w,next=_next;
	};
	bool operator <(const Edge a)const{
		return w>a.w;
	}
}edge[MAXN*MAXN];
int EdgeCount,head[MAXN]; 
int n,cnt,t[MAXN],dis[MAXN];	//g存储图,t存储时间,dis存储距离 
string tmp[MAXN],x[MAXN],y[MAXN];	//tmp存储整个字符串,x存储首字,y存储尾字 
bool used[MAXN];
vector<int> V[MAXN];
void addEdge(int u,int v,int w)
{
	edge[++EdgeCount]=Edge(v,w,head[u]);
	head[u]=EdgeCount;
}
void dijkstra()
{
	priority_queue<Edge> q;
	memset(dis,0x3f,sizeof(dis));
	memset(used,false,sizeof(used));
	dis[1]=0;
	q.push(Edge{1,0,0});
	while(!q.empty()){
		int u=q.top().v;q.pop();
		if(used[u])continue;
		used[u]=1;
		for(int i=head[u];i;i=edge[i].next){
			int v=edge[i].v,w=edge[i].w;
			if(dis[v]>dis[u]+w){
				dis[v]=dis[u]+w;
				q.push(Edge{v,dis[v],0});
			}
		}
	}
	if(dis[n]==0x3f3f3f3f)printf("-1\n");
	else printf("%d\n",dis[n]);
}
int main()
{
	while(cin>>n&&n){
		memset(head,0,sizeof(head));
		for(int i=1;i<=n;i++)V[i].clear();
		set<string> S;
		map<string,int> M;
		for(int i=1;i<=n;i++){	//读入数据 
			cin>>t[i]>>tmp[i];
			x[i]=tmp[i].substr(0,4);
			y[i]=tmp[i].substr(tmp[i].length()-4,4);
			S.insert(x[i]);	//建立set集合 
			S.insert(y[i]);
		}
		if(n==1){	//如果只有一个成语 
			printf("0\n");
			continue; 
		}
		else if(n==2){	//如果有两个成语 
			if(y[1].compare(x[2])==0)printf("%d\n",t[1]);
			else printf("-1\n"); 
			continue;
		}
		cnt=0;	//顶点个数 
		set<string>::iterator it;
		for(it=S.begin();it!=S.end();it++){	//建立map 
			M[*it]=++cnt; 
		}
		for(int i=1;i<=n;i++){	 
			int num=M[x[i]];	//以x[i]汉字开头的成语所在数组的下标
			V[num].push_back(i); 			//更新同一个汉字开头的数组 
		}
		EdgeCount=0;
		for(int i=1;i<=n;i++){	//建图 
			if(M.find(y[i])==M.end())continue;
			int num=M[y[i]];	//以y[i]汉字开头的成语所在数组的下标 
			int len=V[num].size();	//y[i]汉字汉字开头所以 数组的大小 
			for(int j=0;j<len;j++)
				addEdge(i,V[num][j],t[i]); 
			
		} 
		dijkstra(); 
	}
}

SPFA算法

#include <bits/stdc++.h>
#define MAXN 1005
using namespace std;
struct Edge{
	int v,w,next;
	Edge(){};
	Edge(int _v,int _w,int _next){
		v=_v,w=_w,next=_next;
	};
	bool operator <(const Edge a)const{
		return w>a.w;
	}
}edge[MAXN*MAXN];
int EdgeCount,head[MAXN]; 
int ven[MAXN],nums[MAXN];
int n,cnt,t[MAXN],dis[MAXN];	//g存储图,t存储时间,dis存储距离 
string tmp[MAXN],x[MAXN],y[MAXN];	//tmp存储整个字符串,x存储首字,y存储尾字 
vector<int> V[MAXN];
void addEdge(int u,int v,int w)
{
	edge[++EdgeCount]=Edge(v,w,head[u]);
	head[u]=EdgeCount;
}
void SPFA()
{
	queue<int> q;
	memset(dis,0x3f,sizeof(dis));
	memset(ven,0,sizeof(ven));
	memset(nums,0,sizeof(nums));
	dis[1]=0;
	ven[1]=nums[1]=1;
	q.push(1);
	while(!q.empty()){
		int u=q.front();q.pop();
		ven[u]=0;
		for(int i=head[u];i;i=edge[i].next){
			int v=edge[i].v,w=edge[i].w;
			if(dis[v]>dis[u]+w){
				dis[v]=dis[u]+w;
				if(!ven[v]){
					q.push(v);
					ven[v]=1;
					nums[v]++;
					if(nums[v]>cnt){
						printf("-1\n");
						return ;
					}
				}
			}
		}
	}
	if(dis[n]==0x3f3f3f3f)printf("-1\n");
	else printf("%d\n",dis[n]);
	return ;
}
int main()
{
	while(cin>>n&&n){
		memset(head,0,sizeof(head));
		for(int i=1;i<=n;i++)V[i].clear();
		set<string> S;
		map<string,int> M;
		for(int i=1;i<=n;i++){	//读入数据 
			cin>>t[i]>>tmp[i];
			x[i]=tmp[i].substr(0,4);
			y[i]=tmp[i].substr(tmp[i].length()-4,4);
			S.insert(x[i]);	//建立set集合 
			S.insert(y[i]);
		}
		if(n==1){	//如果只有一个成语 
			printf("0\n");
			continue; 
		}
		else if(n==2){	//如果有两个成语 
			if(y[1].compare(x[2])==0)printf("%d\n",t[1]);
			else printf("-1\n"); 
			continue;
		}
		cnt=0;	//顶点个数 
		set<string>::iterator it;
		for(it=S.begin();it!=S.end();it++){	//建立map 
			M[*it]=++cnt; 
		}
		for(int i=1;i<=n;i++){	 
			int num=M[x[i]];	//以x[i]汉字开头的成语所在数组的下标
			V[num].push_back(i); 			//更新同一个汉字开头的数组 
		}
		EdgeCount=0;
		for(int i=1;i<=n;i++){	//建图 
			if(M.find(y[i])==M.end())continue;
			int num=M[y[i]];	//以y[i]汉字开头的成语所在数组的下标 
			int len=V[num].size();	//y[i]汉字汉字开头所以 数组的大小 
			for(int j=0;j<len;j++)
				addEdge(i,V[num][j],t[i]); 
			
		} 
		SPFA(); 
	}
}

SPFA算法之SLF优化

#include <bits/stdc++.h>
#define MAXN 1005
using namespace std;
struct Edge{
	int v,w,next;
	Edge(){};
	Edge(int _v,int _w,int _next){
		v=_v,w=_w,next=_next;
	};
	bool operator <(const Edge a)const{
		return w>a.w;
	}
}edge[MAXN*MAXN];
int EdgeCount,head[MAXN]; 
int ven[MAXN],nums[MAXN];
int n,cnt,t[MAXN],dis[MAXN];	//g存储图,t存储时间,dis存储距离 
string tmp[MAXN],x[MAXN],y[MAXN];	//tmp存储整个字符串,x存储首字,y存储尾字 
vector<int> V[MAXN];
void addEdge(int u,int v,int w)
{
	edge[++EdgeCount]=Edge(v,w,head[u]);
	head[u]=EdgeCount;
}
void SPFA()
{
	deque<int> q;
	memset(dis,0x3f,sizeof(dis));
	memset(ven,0,sizeof(ven));
	memset(nums,0,sizeof(nums));
	dis[1]=0;
	ven[1]=nums[1]=1;
	q.push_back(1);
	int k;	//k记录队列中的个数 
	while(k=q.size()){
		int u=q.front();q.pop_front();
		ven[u]=0;
		for(int i=head[u];i;i=edge[i].next){
			int v=edge[i].v,w=edge[i].w;
			if(dis[v]>dis[u]+w){
				dis[v]=dis[u]+w;
				if(!ven[v]){
					if(cnt>1&&dis[v]<dis[q.front()])q.push_front(v);
					else q.push_back(v);
					ven[v]=1;
					nums[v]++;
					if(nums[v]>cnt){
						printf("-1\n");
						return ;
					}
				}
			}
		}
	}
	if(dis[n]==0x3f3f3f3f)printf("-1\n");
	else printf("%d\n",dis[n]);
	return ;
}
int main()
{
	while(cin>>n&&n){
		memset(head,0,sizeof(head));
		for(int i=1;i<=n;i++)V[i].clear();
		set<string> S;
		map<string,int> M;
		for(int i=1;i<=n;i++){	//读入数据 
			cin>>t[i]>>tmp[i];
			x[i]=tmp[i].substr(0,4);
			y[i]=tmp[i].substr(tmp[i].length()-4,4);
			S.insert(x[i]);	//建立set集合 
			S.insert(y[i]);
		}
		if(n==1){	//如果只有一个成语 
			printf("0\n");
			continue; 
		}
		else if(n==2){	//如果有两个成语 
			if(y[1].compare(x[2])==0)printf("%d\n",t[1]);
			else printf("-1\n"); 
			continue;
		}
		cnt=0;	//顶点个数 
		set<string>::iterator it;
		for(it=S.begin();it!=S.end();it++){	//建立map 
			M[*it]=++cnt; 
		}
		for(int i=1;i<=n;i++){	 
			int num=M[x[i]];	//以x[i]汉字开头的成语所在数组的下标
			V[num].push_back(i); 			//更新同一个汉字开头的数组 
		}
		EdgeCount=0;
		for(int i=1;i<=n;i++){	//建图 
			if(M.find(y[i])==M.end())continue;
			int num=M[y[i]];	//以y[i]汉字开头的成语所在数组的下标 
			int len=V[num].size();	//y[i]汉字汉字开头所以 数组的大小 
			for(int j=0;j<len;j++)
				addEdge(i,V[num][j],t[i]); 
			
		} 
		SPFA(); 
	}
}

发布了19 篇原创文章 · 获赞 0 · 访问量 123

猜你喜欢

转载自blog.csdn.net/weixin_43960284/article/details/105278637