天天看点

Problem : Part Acquisition(最短路径解法二)

problem:Part Acquisition

题目描述:

The cows have been sent on a mission through space to acquire a new milking machine for their barn. They are flying through a cluster of stars containing N (1 <= N <= 50,000) planets, each with a trading post.

The cows have determined which of K (1 <= K <= 1,000) types of objects (numbered 1…K) each planet in the cluster desires, and which products they have to trade. No planet has developed currency, so they work under the barter system: all trades consist of each party trading exactly one object (presumably of different types).

The cows start from Earth with a canister of high quality hay (item 1), and they desire a new milking machine (item K). Help them find the best way to make a series of trades at the planets in the cluster to get item K. If this task is impossible, output -1.

给出N条边,单向的。再给出数字K.问从1号点到K点号,最短路上经过多少个点。

输入格式:

  • Line 1: Two space-separated integers, N and K.
  • Lines 2…N+1: Line i+1 contains two space-separated integers, a_i and b_i respectively, that are planet i’s trading trading products. The planet will give item b_i in order to receive item a_i.

输出格式:

  • Line 1: One more than the minimum number of trades to get the milking machine which is item K (or -1 if the cows cannot obtain item K).

样例输入:

6 5

1 3

3 2

2 3

3 1

2 5

5 4

样例输出:

4

我们先得把输入格式翻译一下:

*第1行:两个以空格分隔的整数,N和K.

*第2…N + 1行:第i + 1行包含两个空格分隔的整数,a_i和b_i,分别是行星i的交易交易产品。行星将给出项目b_i以便接收项目a_i。

看到这,我们就可以画样例图了:

这就是这题给的样例:

Problem : Part Acquisition(最短路径解法二)

(注意,这题他的连线是单向的)

从1到5经过了:1----3----2----5四个点,所以答案是4.

那我们想想,这个题目怎么做呢?想一下上篇博客写的方法,费洛伊德算法可以做出来吗?(详见https://blog.csdn.net/qq_42884520/article/details/86678329),答案应该是不行的,至少本蒟蒻是做不出的 ,因为费洛伊德算法常针对的是双向的线,而此题是单向的,所以我们得想其它的方法了:没错,这就是今天要使用的Dijkstra算法,那什么是Dijkstra算法呢?让我们查查百度百科:(https://baike.baidu.com/item/迪杰斯特拉算法/4049057?fromtitle=Dijkstra算法&fromid=215612&fr=aladdin)

看完后是不是一脸懵比?没事,让我们看看一个例子就好啦吗:

Problem : Part Acquisition(最短路径解法二)

我们看看这个图,我们怎么办,很简单,我们写一个循环,第一轮先把dis[1]打上标记:做一个替换 dis[2]=2,dis[3]=4,dis[4]=7;

第二轮我们把dis[2]打上标记,使得:dis[3]=2+1=3 dis[5]=2+2=4;

第三轮把dis[3]打上标记:使得:dis[4]=4;

接下来的循环把4,5都打上标记,这样,整个图的最短路径都能求出来啦

但是这个方法不能用来处理带有负数的值,不然就会产生错误答案,不信自己去推一推。

这个算法的思想是什么呢:

就是从一个点出发,到一个点的最短路径必然会经过一个中转点,我们只要求出中转点的最短路径,答案就显而易见了。

代码实现:

(设起点为s,pre[v]为v的前驱节点,用来输出路径)

1.初始化:dis[v]=0x7f,dis[s]=0;pre[s]=0;

2.for(int i=1;i<=n;i++)

1.找一个未访问过的u点,使得dis[u]最小;

2.标记u

3.for与u相连的每个未确定最短路径的顶点v。

if(dis[u]+w[u][v]<dis[v])

{

dis[v]=dis[u]+w[u][v];

pre[v]=u;

}

3.结束。

有了以上这些基础,在重新回去看看题,相信你可以做出来的

下面附上AC代码和解析:

#include<cstdio>
#include<iostream>
#define INF 10000005
using namespace std;

int map[1005][1005],dis[1005],path[1005],vis[1005];
int n,k;

void read(int &x) 
{
    char ch;
    bool ok;
    for(ok=0,ch=getchar(); !isdigit(ch); ch=getchar()) if(ch=='-') ok=1;
    for(x=0; isdigit(ch); x=x*10+ch-'0',ch=getchar());
    if(ok) x=-x;
}

void dijkstra() 
{
	for(int i=1;i<=k;i++) 
	{
		dis[i]=map[1][i];
		if(i!=1&&map[1][i]<INF) //记录当前能到达的点的前驱
			path[i]=1;
	}
	vis[1]=1;

	int min,v;
	for(int i=1;i<k;i++) 
	{
		min=INF;
		v=1;
		for(int j=1;j<=k;j++) 
		{
			if(!vis[j]&&dis[j]<min)
			{
				min=dis[j];
				v=j;
			}
		}
		vis[v]=1;

		for(int j=1;j<=k;j++) 
		{
			if(!vis[j]&&dis[j]>dis[v]+map[v][j]) 
			{
				dis[j]=dis[v]+map[v][j];
				path[j]=v; //记录到达j点的最短路径的前驱
			}
		}
	}
}

int main() 
{
	read(n);read(k);
	for(int i=1;i<=k;i++) 
	{
		for(int j=1;j<=k;j++) 
		{
			//对vis数组,path数组,map数组进行初始化
			map[i][j]=INF;
		}
		vis[i]=0;
		path[i]=-1;
	}

	int u,v;
	for(int i=1;i<=n;i++) 
	{
		read(u);read(v);
		map[u][v]=1; //因为要计算通过的顶点的个数,所以把map初始化1 
	}
	dijkstra();
	if(dis[k]==INF) 
	{
		//判断两点间是否能够到达
		printf("-1\n");
	} 
	else 
	{
		printf("%d\n",dis[k]+1); //输出需要经过的顶点的个数 ,顶点数是边的数目加1
	}
	return 0;

}

           

谢谢各位大佬的观看,谢谢,谢谢。

继续阅读