九度OJ 1162 I wanna go home

这两天做题被虐的难受..老是莫名其妙的不通过 ..也一直没更博

写了这道题,AC了,算是找回点自信,还是在机试指南的提示下做出来的

嗯,看下题目吧

—————————————————————————————————————————————————————

题目描述:

    The country is facing a terrible civil war----cities in the country are divided into two parts supporting different leaders. As a merchant, Mr. M does not pay attention to politics but he actually knows the severe situation, and your task is to help him reach home as soon as possible. 
    "For the sake of safety,", said Mr.M, "your route should contain at most 1 road which connects two cities of different camp."
    Would you please tell Mr. M at least how long will it take to reach his sweet home?

输入:

    The input contains multiple test cases.
    The first line of each case is an integer N (2<=N<=600), representing the number of cities in the country.
    The second line contains one integer M (0<=M<=10000), which is the number of roads.
    The following M lines are the information of the roads. Each line contains three integers A, B and T, which means the road between city A and city B will cost time T. T is in the range of [1,500].
    Next part contains N integers, which are either 1 or 2. The i-th integer shows the supporting leader of city i. 
    To simplify the problem, we assume that Mr. M starts from city 1 and his target is city 2. City 1 always supports leader 1 while city 2 is at the same side of leader 2. 
    Note that all roads are bidirectional and there is at most 1 road between two cities.
Input is ended with a case of N=0.

输出:

    For each test case, output one integer representing the minimum time to reach home.
    If it is impossible to reach home according to Mr. M's demands, output -1 instead.

样例输入:
2
1
1 2 100
1 2
3
3
1 2 100
1 3 40
2 3 50
1 2 1
5
5
3 1 200
5 3 150
2 5 160
4 3 170
4 2 170
1 2 2 2 1
0
样例输出:
100
90
540
 分析:基本思想还是迪杰斯特拉算法,与常规不同的是,只允许从一个阵营到另一个阵营的路只允许最多一条,这该怎么翻译成数学语言呢?其实也就是“有去无回”,只要到了另外一个阵营,不能从其他路往原来的阵营走回去就可以了,所以,录入边信息的时候,跨阵营的边只单向录入,过了另一个阵营就没有回头路了。

还有点无关话题需要注意:当需要输出路径的时候,定义一个pre[N]数组,在更新邻边的时候,存放更新结点的先驱结点为当前节点,这样通过栈或队列就可以实现倒叙或顺序输出路径

代码如下:

#include <stdio.h>
#include <vector>
using namespace std;

struct E{
	int start;
	int next;
	int cost;
}buff[10001];

vector<E> edge[10010];
int Cost[601];
bool mark[601];
int camp[601];
int main(int argc, char** argv) {
	int N,M;
	while(scanf("%d",&N)!=EOF)
	{
		if(N==0) break;
		scanf("%d",&M);
		int i;
		//初始化vector 
		for(i=1;i<=N;i++) edge[i].clear();
		//输入道路信息,暂存在数组里 
		for(i=1;i<=M;i++)
		{
			scanf("%d%d%d",&buff[i].start,&buff[i].next,&buff[i].cost);
		} 
		//输入阵营信息
		for(i=1;i<=N;i++)
		{
			scanf("%d",&camp[i]);
		} 
		//正式录入边信息
		for(i=1;i<=M;i++)
		{
			int a=buff[i].start;
			int b=buff[i].next;
            E tmp;
            tmp.cost=buff[i].cost;
			//如果是同一阵营则可双向,录入两次 
			if(camp[a]==camp[b])
			{   tmp.start=a;
				tmp.next=b;
				edge[a].push_back(tmp);
				tmp.start=b;
				tmp.next=a;
				edge[b].push_back(tmp);
			}
			//如果不是同一阵营,只录入从阵营1->2 
			if(camp[a]!=camp[b])
			{
				if(camp[a]==1){
					tmp.start=a;
					tmp.next=b;
					edge[a].push_back(tmp);
				}
				else
				{   
				    tmp.start=b;
					tmp.next=a;
					edge[b].push_back(tmp);
				} 
			}
		}//录入结束
		 
		//初始化Cost
		for(i=1;i<=N;i++) 
		{
			Cost[i]=-1;
			mark[i]=false;
		}
		 
		int newP=1;
		Cost[1]=0;
		mark[1]=true; 
		//只循环N-1次就可以了 
		for(i=1;i<N;i++)
		{
		//更新新成员的临边信息
		int j;
		for(j=0;j<edge[newP].size();j++)
		{
			int t =edge[newP][j].next;
			int c=edge[newP][j].cost;
			//如果已经在集合中,则跳过 
			if(mark[t]==true) continue;
			//如果距离临点的距离可更新 
			if(Cost[t]==-1||Cost[t]>Cost[newP]+c)
			{
				Cost[t]=Cost[newP]+c;
			}
		} 
		
		//选取下一个新点
		int min=123123123;
		for(j=1;j<=N;j++)
		{
			if(mark[j]==true) continue;
			if(Cost[j]==-1) continue;
			if(Cost[j]<min)
			{
			  	min=Cost[j];
			  	newP=j;
			}
		} 
		
		mark[newP]=true;
		
		
		}//大for循环 
		if(Cost[2]!=-1)
		printf("%d\n",Cost[2]);
		else
		printf("%d\n",-1);
	}//最外层循环 
	
	
	
	
	
	
	
	
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值