zoj 2750 Idiomatic Phrases Game

题目大意:

    成语接龙游戏,给定一些成语,该组成语中第1个和最后一个必须是给定的两个成语。在这组成语中,前一个成语的最后一个汉字必须和后一个成语的第一个汉字相同。在游戏过程中,Tom有一本字典,他必须从字典中选用成语。字典中每个成语都有一个权值T,表示选用这个成语后,Tom需要花时间T才能找到下一个合适的成语。你的任务是编写程序,给定字典,计算Tom至少需要花多长时间才能找到一个满足条件的成语组。注意,字典中第1个和最后一个成语为游戏中给定的起始和目标成语。输入文件最后一行为N = 0,代表输入结束。

分析:

   假设用图中的顶点代表字典中的每个成语,如果第i个成语的最后一个汉字跟第j个成语的第一个汉字相同,则画一条有向边,由顶点i 指向顶点j,权值为题目中所提到的时间T:选用第i个成语后,Tom需要花时间T才能找到下一个合适的成语。这样,样例输入中两个测试数据所构造的有向网如下图(a)和(b)所示。


构造好有向网后,问题就转化成求一条从顶点0到顶点N-1的一条最短路径,如果从顶点0到顶点N-1没有路径,则输出-1。


#include <iostream>
#include <cstring>
#include <cstdio>

using namespace std;

const int MAXN = 1010;
const int INF = 10000010;


struct Idiom
{
	char front[5],back[5];//每个成语的前一个字和后一个字
	int T;//查找单词所花费的时间
};

Idiom dic[MAXN];//存放每个成语的属性
int S[MAXN];
int Edge[MAXN][MAXN];//储存图
int dist[MAXN];//记录从原点到每个顶点的最短路径
int n;

void Dijkstra(int v0)
{
	int i, j;
	for (i = 0; i < n; ++i)
	{
		dist[i] = Edge[v0][i];
		S[i] = 0;
	}
	S[v0] = 1, dist[v0] = 0;

	for (i = 1; i < n; ++i)
	{
		int MIN = INF, v = v0;
		for (j = 0; j < n; ++j)
		{
			if(!S[j] && MIN > dist[j])
			{
				MIN = dist[j];
				v = j;
			}
		}
		S[v] = 1;
		for (j = 0; j < n; ++j)
		{
			if(!S[j] && Edge[v][j] < INF && dist[j] > dist[v] + Edge[v][j])
				dist[j] = dist[v] + Edge[v][j];
		}
	}
}

int main()
{
	int i, j, k;
	while (cin>>n)
	{
		if(n == 0)
			break;
		for (i = 0; i < n; ++i)
		{
			char s[50];
			cin>>dic[i].T>>s;
			int len = strlen(s);
			for (j = 0, k = len-1; j < 4; ++j, --k)//记录第i个成语的第一个字和最后一个字
			{
				dic[i].front[j] = s[j];
				dic[i].back[3-j] = s[k];
			}
			dic[i].back[4] = dic[i].front[4] = '\0';
		}

		for (i = 0; i < n; ++i)//建图
		{
			for (j = 0; j < n; ++j)
			{
				Edge[i][j] = INF;
				if(i == j)
					continue;
				if(strcmp( dic[i].back, dic[j].front ) == 0)//说明第i个成语的最后一个字与第j个成语的第一个字相同,则,连一条从i到j的边
					Edge[i][j] = dic[i].T;//权值为花费的时间
			}
		}
		Dijkstra( 0 );
		if(dist[n-1] < INF)
			cout<<dist[n-1]<<endl;
		else
			cout<<"-1"<<endl;
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值