2020.7.28【算协集训】朴素版Dijkstra+Floyd

网页链接:传送门
密码:HPUACM

A - 最短路 (HDU-2544)

在每年的校赛里,所有进入决赛的同学都会获得一件很漂亮的t-shirt。但是每当我们的工作人员把上百件的衣服从商店运回到赛场的时候,却是非常累的!所以现在他们想要寻找最短的从商店到赛场的路线,你可以帮助他们吗?
Input
输入包括多组数据。每组数据第一行是两个整数N、M(N<=100,M<=10000),N表示成都的大街上有几个路口,标号为1的路口是商店所在地,标号为N的路口是赛场所在地,M则表示在成都有几条路。N=M=0表示输入结束。接下来M行,每行包括3个整数A,B,C(1<=A,B<=N,1<=C<=1000),表示在路口A与路口B之间有一条路,我们的工作人员需要C分钟的时间走过这条路。
输入保证至少存在1条商店到赛场的路线。
Output
对于每组输入,输出一行,表示工作人员从商店走到赛场的最短时间

Sample InputSample Output
2 1
1 2 3
3 3
1 2 5
2 3 5
3 1 2
0 0
3
2

分析

这题是dijkstra的模板题,基本上套板子就可以。只需要注意这个是无向图,从 A A A B B B 需要花 C C C 的代价,那么从 B B B A A A 也是一样的。
而因为这题数据比较小,用Floyd也可以。代码两种做法都放上了。
(不管是哪种做法其实都可以叫模板题。。)

代码

  1. dijkstra的做法

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    typedef long long ll;
    const ll maxn=110;
    const ll INF=0x3f;
    
    int N,M,A,B,C;
    int G[maxn][maxn],dis[maxn];
    bool bj[maxn];
    
    void dijkstra()
    {
    	memset(dis,INF,sizeof(dis));
    	memset(bj,false,sizeof(bj));
    	dis[1]=0;
    	for(int i=1;i<=N-1;i++)
    	{
    		int t=-1;
    		for(int j=1;j<=N;j++)
    		{
    			if(!bj[j] && (t==-1 || dis[t]>dis[j]))
    			{
    				t=j;
    			}
    		}	
    		bj[t]=true;
    		for(int j=1;j<=N;j++)
    		{
    			if(!bj[j])
    			{
    				dis[j]=min(dis[j],dis[t]+G[t][j]);
    			}
    		}	
    	}
    }
    
    int main()
    {
    	while(~scanf("%d%d",&N,&M))
    	{
    		if(N==0 && M==0)	break;
    		memset(G,INF,sizeof(G));
    		for(int i=0;i<M;i++)
    		{
    			scanf("%d%d%d",&A,&B,&C);
    			G[A][B]=C;	//无向图,因此两个起点都得存一下
    			G[B][A]=C;
    		}
    		dijkstra();
    		printf("%d\n",dis[N]);
    	}
    	return 0;
    }
    
  2. Floyd的做法

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    typedef long long ll;
    const ll maxn=110;
    const ll INF=0x3f3f3f3f;
    
    int N,M,A,B,C;
    int dis[maxn][maxn];
    
    void Floyd()
    {
    	for(int k=1;k<=N;k++)
    		for(int i=1;i<=N;i++)
    			for(int j=1;j<=N;j++)
    				dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
    }
    
    int main()
    {
    	while(~scanf("%d%d",&N,&M))
    	{
    		if(N==0 && M==0) 	break;
    		memset(dis,INF,sizeof(dis));
    		for(int i=0;i<N;i++)	dis[i][i]=0;
    		for(int i=0;i<M;i++)
    		{
    			scanf("%d%d%d",&A,&B,&C);
    			dis[A][B]=min(dis[A][B],C);
    			dis[B][A]=min(dis[B][A],C);
    		}
    		Floyd();
    		printf("%d\n",dis[1][N]);
    	}
    	return 0;
    }
    

B - 畅通工程续 (HDU-1874)

某省自从实行了很多年的畅通工程计划后,终于修建了很多路。不过路多了也不好,每次要从一个城镇到另一个城镇时,都有许多种道路方案可以选择,而某些方案要比另一些方案行走的距离要短很多。这让行人很困扰。
现在,已知起点和终点,请你计算出要从起点到终点,最短需要行走多少距离。
Input
本题目包含多组数据,请处理到文件结束。
每组数据第一行包含两个正整数N和M(0<N<200,0<M<1000),分别代表现有城镇的数目和已修建的道路的数目。城镇分别以0~N-1编号。
接下来是M行道路信息。每一行有三个整数A,B,X(0<=A,B<N,A!=B,0<X<10000),表示城镇A和城镇B之间有一条长度为X的双向道路。
再接下一行有两个整数S,T(0<=S,T<N),分别代表起点和终点。
Output
对于每组数据,请在一行里输出最短需要行走的距离。如果不存在从S到T的路线,就输出-1.

Sample InputSample Output
3 3
0 1 1
0 2 3
1 2 1
0 2
3 1
0 1 1
1 2
2
-1

分析

这题是Floyd的模板题。有 N N N 个点 M M M 条边, A A A B B B 有条路需要花费 X X X ,问你从 S S S T T T 是否可达,最短花费是多少。
这题有一些坑点:①重边的处理;②起点和终点相同的情况。重边是因为测试数据同一条路径可能会出现很多次,然后值都不一样,所以我们需要取它最小的那次花费。起点和终点相同,就只需要输出 0 0 0 ,这个在一开始定义初值的时候就可以完成。

代码

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
const ll maxn=210;
const ll INF=0x3f3f3f3f;	//INF要开大点

int N,M,A,B,X,S,T;
int dis[maxn][maxn];

void Floyd()
{
	for(int k=0;k<N;k++)
		for(int i=0;i<N;i++)
			for(int j=0;j<N;j++)
				dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
}

int main()
{
	while(~scanf("%d%d",&N,&M))
	{
		memset(dis,INF,sizeof(dis));
		for(int i=0;i<N;i++)	dis[i][i]=0;	//i和i之间只需要花费0
		for(int i=0;i<M;i++)
		{
			scanf("%d%d%d",&A,&B,&X);
			dis[A][B]=min(dis[A][B],X);	//注意这里一定要判断以前有没有存过一样的路,这次的路是否比以前的路更近了
			dis[B][A]=min(dis[B][A],X);
		}
		scanf("%d%d",&S,&T);
		Floyd();
		if(dis[S][T]==INF)	printf("-1\n");
		else	printf("%d\n",dis[S][T]);
	}
	return 0;
}

C - Frogger (POJ-2253)

Freddy Frog is sitting on a stone in the middle of a lake. Suddenly he notices Fiona Frog who is sitting on another stone. He plans to visit her, but since the water is dirty and full of tourists’ sunscreen, he wants to avoid swimming and instead reach her by jumping.
Unfortunately Fiona’s stone is out of his jump range. Therefore Freddy considers to use other stones as intermediate stops and reach her by a sequence of several small jumps.
To execute a given sequence of jumps, a frog’s jump range obviously must be at least as long as the longest jump occuring in the sequence.
The frog distance (humans also call it minimax distance) between two stones therefore is defined as the minimum necessary jump range over all possible paths between the two stones.
You are given the coordinates of Freddy’s stone, Fiona’s stone and all other stones in the lake. Your job is to compute the frog distance between Freddy’s and Fiona’s stone.
Input
The input will contain one or more test cases. The first line of each test case will contain the number of stones n (2<=n<=200). The next n lines each contain two integers xi,yi (0 <= xi,yi <= 1000) representing the coordinates of stone #i. Stone #1 is Freddy’s stone, stone #2 is Fiona’s stone, the other n-2 stones are unoccupied. There’s a blank line following each test case. Input is terminated by a value of zero (0) for n.
Output
For each test case, print a line saying “Scenario #x” and a line saying “Frog Distance = y” where x is replaced by the test case number (they are numbered from 1) and y is replaced by the appropriate real number, printed to three decimals. Put a blank line after each test case, even after the last one.

Sample InputSample Output
2
0 0
3 4

3
17 4
19 4
18 5

0
Scenario #1
Frog Distance = 5.000

Scenario #2
Frog Distance = 1.414

分析

这题就不是纯粹地套模板就可以水过去的了!需要进行略微的变形。
先说下题意:青蛙🐸 F r e d d y Freddy Freddy 想去找青蛙🐸 F i o n a Fiona Fiona F r e d d y Freddy Freddy 在第一块石头, F i o n a Fiona Fiona 在第二块石头,二者之间可能有另外一些石头。 F r e d d y Freddy Freddy 必须要从石头上跳到 F i o n a Fiona Fiona 那而不踩到池水里,因此你得到每块石头的坐标后,需要计算可行路径中的最小的必要跳跃距离(某条路径的必要跳跃距离,即这条路径中单次跳跃的最远跳跃距离),让🐸确定他的跳跃距离至少是多少,才可以到达目的地。

题意用通俗的话讲,就是给定平面一些点的坐标,问从一号点到二号点的所有路径中最长边最短的值是多少。

以第二组测试数据为例:
第一块石头 ( 17 , 4 ) (17,4) (17,4) 与第二块石头 ( 19 , 4 ) (19,4) (19,4) 间的距离是 2 2 2 ——最大距离是 2 2 2
第一块石头 ( 17 , 4 ) (17,4) (17,4) 与第三块石头 ( 18 , 5 ) (18,5) (18,5) 间的距离是 2 \sqrt{2} 2 ;第二块石头 ( 19 , 4 ) (19,4) (19,4) 与第三块石头 ( 18 , 5 ) (18,5) (18,5) 间的距离是 2 \sqrt{2} 2 ——最大距离是 2 \sqrt{2} 2
因此第一块石头到第二块石头的最小的最大距离是 2 ≈ 1.414 \sqrt{2}≈1.414 2 1.414

而这道题不管是 D i j k s t r a Dijkstra Dijkstra 还是 F l o y d Floyd Floyd 都可以做。现在以 F l o y d Floyd Floyd 的做法为例:定义数组 d i s [ i ] [ j ] dis[i][j] dis[i][j] ,表示从 i i i j j j 这条路上最小的必要跳跃距离。如果说 “ i − j ” “i-j” ij 有一条路, “ i − k − j ” “i-k-j” ikj 也有一条路,那么就需要判断一下这两条路中哪一条路的必要跳跃距离最小。对于路 “ i − k − j ” “i-k-j” ikj 来说,它的必要跳跃距离是 m a x ( d i s [ i ] [ k ] , d i s [ k ] [ j ] ) max(dis[i][k],dis[k][j]) max(dis[i][k],dis[k][j]) ;而对于路 “ i − j ” “i-j” ij ,目前它的必要跳跃距离就是 d i s [ i ] [ j ] dis[i][j] dis[i][j] 。将二者比较一下,取其中较小的那个值赋值给 d i s [ i ] [ j ] dis[i][j] dis[i][j] ,这样 d i s [ i ] [ j ] dis[i][j] dis[i][j] 中存放的就是从 i i i j j j 这条路上最小的必要跳跃距离了。

代码

  1. Floyd的做法
    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    using namespace std;
    typedef long long ll;
    const ll maxn=210;
    const ll INF=0x3f3f3f3f;
    
    int T,x,y,cnt;
    double dis[maxn][maxn];	//d[i][j]存放从i到j这条路上最小的必要跳跃距离
    pair<int,int> p[maxn];	//p[i]存放第i块石头的坐标
    
    double d(pair<int,int> a,pair<int,int> b)	//计算两点间的距离
    {
    	return sqrt((double)(a.first-b.first)*(a.first-b.first)+(a.second-b.second)*(a.second-b.second));	//一定要把整型转换为实型,否则会CE
    }
    
    void Floyd()
    {
    	for(int k=0;k<T;k++)
    		for(int i=0;i<T;i++)
    			for(int j=0;j<T;j++)
    			if(dis[i][j]>max(dis[i][k],dis[k][j]))
    				dis[i][j]=max(dis[i][k],dis[k][j]);	//存放从i到j这条路上最小的必要跳跃距离
    }
    
    int main()
    {
    	while(~scanf("%d",&T))
    	{
    		if(T==0) 	break;
    		for(int i=0;i<T;i++)
    		{
    			scanf("%d%d",&x,&y);
    			p[i]=make_pair(x,y);	//存放石头坐标
    		}
    		for(int i=0;i<T;i++) 
    		{
    			for(int j=i;j<T;j++)
    			{
    				if(i==j)	dis[i][j]=d(p[i],p[j]);
    				else	dis[i][j]=dis[j][i]=d(p[i],p[j]);
    			}
    		}
    		Floyd();
    		cnt++;
    		printf("Scenario #%d\n",cnt);
    		printf("Frog Distance = %.3lf\n\n",dis[0][1]);
    	}
    	return 0;
    }
    
  2. dijkstra的做法
    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    using namespace std;
    typedef long long ll;
    const ll maxn=210;
    const ll INF=0x3f3f3f3f;
    
    int T,x,y,cnt;
    double G[maxn][maxn],dis[maxn];
    bool bj[maxn];
    pair<int,int> p[maxn];
    
    double d(pair<int,int> a,pair<int,int> b)	//计算两点间的距离
    {
    	return sqrt((double)(a.first-b.first)*(a.first-b.first)+(a.second-b.second)*(a.second-b.second));	//一定要把整型转换为实型,否则会CE
    }
    
    void dijkstra()
    {
    	for(int i=0;i<T;i++)
    	{
    		dis[i]=INF;	//dis不能用memset赋值,否则会出错(就因为这个改了半天bug)
    		bj[i]=false;
    	}
    //	memset(bj,false,sizeof(bj));
    	dis[0]=0;
    	for(int i=0;i<T-1;i++)
    	{
    		int t=-1;
    		for(int j=0;j<T;j++)
    		{
    			if(!bj[j] && (t==-1 || dis[t]>dis[j]))
    			{
    				t=j;
    			}
    		}	
    		bj[t]=true;
    		for(int j=0;j<T;j++)
    		{
    			if(!bj[j] && dis[j]>max(dis[t],G[t][j]))
    			{
    				dis[j]=max(dis[t],G[t][j]);
    			}
    		}	
    	}
    }
    
    int main()
    {
    	while(~scanf("%d",&T))
    	{
    		if(T==0)	break;
    		memset(G,INF,sizeof(G));
    		for(int i=0;i<T;i++)
    		{
    			scanf("%d%d",&x,&y);
    			p[i]=make_pair(x,y);
    		}
    		for(int i=0;i<T;i++) 
    		{
    			for(int j=i;j<T;j++)
    			{
    				if(i==j)	G[i][j]=d(p[i],p[j]);
    				else	G[i][j]=G[j][i]=d(p[i],p[j]);
    			}
    		}
    		dijkstra();
    		cnt++;
    		printf("Scenario #%d\n",cnt);
    		printf("Frog Distance = %.3lf\n\n",dis[1]);
    	}
    	return 0;
    }
    

D - 一个人的旅行 (HDU-2066)

虽然草儿是个路痴(就是在杭电待了一年多,居然还会在校园里迷路的人,汗),但是草儿仍然很喜欢旅行,因为在旅途中 会遇见很多人(白马王子,KaTeX parse error: Double superscript at position 3: ^0^̲ ),很多事,还能丰富自己的阅历,还可以看美丽的风景……草儿想去很多地方,她想要去东京铁塔看夜景,去威尼斯看电影,去阳明山上看海芋,去纽约纯粹看雪景,去巴黎喝咖啡写信,去北京探望孟姜女……眼看寒假就快到了,这么一大段时间,可不能浪费啊,一定要给自己好好的放个假,可是也不能荒废了训练啊,所以草儿决定在要在最短的时间去一个自己想去的地方!因为草儿的家在一个小镇上,没有火车经过,所以她只能去邻近的城市坐火车(好可怜啊~)。
Input
输入数据有多组,每组的第一行是三个整数T,S和D,表示有T条路,和草儿家相邻的城市的有S个,草儿想去的地方有D个;
接着有T行,每行有三个整数a,b,time,表示a,b城市之间的车程是time小时;(1=<(a,b)<=1000;a,b 之间可能有多条路)
接着的第T+1行有S个数,表示和草儿家相连的城市;
接着的第T+2行有D个数,表示草儿想去地方。
Output
输出草儿能去某个喜欢的城市的最短时间。

Sample InputSample Output
6 2 3
1 3 5
1 4 7
2 8 12
3 8 4
4 9 12
9 10 2
1 2
8 9 10
9

分析

这题我用了一个比较骚的操作。
其他城市的编号都 ≥ 1 ≥1 1 ,那么我们就可以设草儿家的编号是 0 0 0
草儿家临近的城市可能不止一个,而且草儿只能去邻近的城市坐火车,说明起始点不止一个,但是我们可以让草儿家与这些相邻的城市的距离弄成 0 0 0 ,就还是可以让编号为 0 0 0 的点作为起始点了。
草儿喜欢的城市可能不止一个,且只需要计算到其中某个城市的最短时间就可以了,说明终点不止一个,但是我们可以让之前没有出现过的编号作为终点,终点与草儿喜欢的城市的距离弄成 0 0 0 ,就只需要计算从编号为 0 0 0 的点开始,到编号为 n n n 的点结束,这一段路程的最短时间是多少。

其他套模板就vans!非常地妙 😄

代码

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
const ll maxn=1010;
const ll INF=0x3f3f3f3f;

int T,S,D,n,a,b,x,time;
int G[maxn][maxn],dis[maxn];
bool bj[maxn];

void dijkstra()
{
	memset(dis,INF,sizeof(dis));
	memset(bj,false,sizeof(bj));
	dis[0]=0;
	for(int i=0;i<=n-1;i++)
	{
		int t=-1;
		for(int j=0;j<=n;j++)
		{
			if(!bj[j] && (t==-1 || dis[t]>dis[j]))
			{
				t=j;
			}
		}	
		bj[t]=true;
		for(int j=0;j<=n;j++)
		{
			if(!bj[j])
			{
				dis[j]=min(dis[j],dis[t]+G[t][j]);
			}
		}	
	}
}

int main()
{
	while(~scanf("%d%d%d",&T,&S,&D))
	{
		memset(G,INF,sizeof(G));
		n=0;
		for(int i=0;i<T;i++)
		{
			scanf("%d%d%d",&a,&b,&time);
			G[a][b]=min(G[a][b],time);
			G[b][a]=min(G[b][a],time);
			n=max(n,a);
			n=max(n,b);
		}
		n++;	//n是之前都没有出现过的编号(把它作为终点)
		for(int i=0;i<S;i++)	//草儿家(0)与邻近城市的距离是0
		{
			scanf("%d",&x);
			G[0][x]=G[x][0]=0;
		}
		for(int i=0;i<D;i++)	//草儿喜欢的城市与终点(n)的距离是0
		{
			scanf("%d",&x);
			G[x][n]=G[n][x]=0;
		}	
		dijkstra();
		printf("%d\n",dis[n]);	//输出到结束点的最短时间
	}
	return 0;
}

E - Choose the best route (HDU-2680)

One day , Kiki wants to visit one of her friends. As she is liable to carsickness , she wants to arrive at her friend’s home as soon as possible . Now give you a map of the city’s traffic route, and the stations which are near Kiki’s home so that she can take. You may suppose Kiki can change the bus at any station. Please find out the least time Kiki needs to spend. To make it easy, if the city have n bus stations ,the stations will been expressed as an integer 1,2,3…n.
Input
There are several test cases.
Each case begins with three integers n, m and s,(n<1000,m<20000,1=<s<=n) n stands for the number of bus stations in this city and m stands for the number of directed ways between bus stations .(Maybe there are several ways between two bus stations .) s stands for the bus station that near Kiki’s friend’s home.
Then follow m lines ,each line contains three integers p , q , t (0<t<=1000). means from station p to station q there is a way and it will costs t minutes .
Then a line with an integer w(0<w<n), means the number of stations Kiki can take at the beginning. Then follows w integers stands for these stations.
Output
The output contains one line for each data set : the least time Kiki needs to spend ,if it’s impossible to find such a route ,just output “-1”.

Sample InputSample Output
5 8 5
1 2 2
1 5 3
1 3 4
2 4 7
2 5 6
2 3 5
3 5 1
4 5 1
2
2 3
4 3 4
1 2 3
1 3 4
2 3 2
1
1
1
-1

分析

这题和上一题的操作差不多。这题给出了一些可以出发的点和目标点(上题连目标点都莫得),要求出起点到终点的最短时间。
其他点的编号都 ≥ 1 ≥1 1 ,那么我们就可以设主角的初始点编号是 0 0 0
可以出发的点可能不止一个,说明起始点不止一个,但是我们可以让主角的初始点与这些可以出发的点的距离弄成 0 0 0 ,就还是可以让编号为 0 0 0 的点作为起始点了。
这样之后看只需要计算从编号为 0 0 0 的点开始,到编号为 s s s 的点结束的最短时间是多少。

其他套模板就vans!非常地妙

代码

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
const ll maxn=1010;
const ll INF=0x3f3f3f3f;

int n,m,s,w,x,p,q,t;
int G[maxn][maxn],dis[maxn];
bool bj[maxn];

void dijkstra()
{
	memset(dis,INF,sizeof(dis));
	memset(bj,false,sizeof(bj));
	dis[0]=0;
	for(int i=0;i<=n-1;i++)
	{
		int t=-1;
		for(int j=0;j<=n;j++)
		{
			if(!bj[j] && (t==-1 || dis[t]>dis[j]))
			{
				t=j;
			}
		}	
		bj[t]=true;
		for(int j=0;j<=n;j++)
		{
			if(!bj[j])
			{
				dis[j]=min(dis[j],dis[t]+G[t][j]);
			}
		}	
	}
}

int main()
{
	while(~scanf("%d%d%d",&n,&m,&s))
	{
		memset(G,INF,sizeof(G));
		for(int i=0;i<m;i++)
		{
			scanf("%d%d%d",&p,&q,&t);
			G[p][q]=min(G[p][q],t);	//避免重边带来的干扰
		}
		scanf("%d",&w);
		for(int i=0;i<w;i++)	//初始点与可以出发的点的距离是0 
		{
			scanf("%d",&x);
			G[0][x]=G[x][0]=0;
		}
		dijkstra();
		if(dis[s]==INF)	printf("-1\n");
		else	printf("%d\n",dis[s]);
	}
	return 0;
}

F - Minimum Transport Cost (HDU-1385)

These are N cities in Spring country. Between each pair of cities there may be one transportation track or none. Now there is some cargo that should be delivered from one city to another. The transportation fee consists of two parts:
The cost of the transportation on the path between these cities, and

a certain tax which will be charged whenever any cargo passing through one city, except for the source and the destination cities.

You must write a program to find the route which has the minimum cost.
Input
First is N, number of cities. N = 0 indicates the end of input.

The data of path cost, city tax, source and destination cities are given in the input, which is of the form:

a11 a12 … a1N
a21 a22 … a2N

aN1 aN2 … aNN
b1 b2 … bN

c d
e f

g h

where aij is the transport cost from city i to city j, aij = -1 indicates there is no direct path between city i and city j. bi represents the tax of passing through city i. And the cargo is to be delivered from city c to city d, city e to city f, …, and g = h = -1. You must output the sequence of cities passed by and the total cost which is of the form:
Output
From c to d :
Path: c–>c1–>…–>ck–>d
Total cost : …


From e to f :
Path: e–>e1–>…–>ek–>f
Total cost : …

Note: if there are more minimal paths, output the lexically smallest one. Print a blank line after each test case.

Sample InputSample Output
5
0 3 22 -1 4
3 0 5 -1 -1
22 5 0 9 20
-1 -1 9 0 4
4 -1 20 4 0
5 17 8 3 1
1 3
3 5
2 4
-1 -1
0
From 1 to 3 :
Path: 1–>5–>4–>3
Total cost : 21

From 3 to 5 :
Path: 3–>4–>5
Total cost : 16

From 2 to 4 :
Path: 2–>1–>5–>4
Total cost : 17

分析

题意:有 N N N 个城市,给出这些城市之间距离的邻接矩阵,-1代表那两个城市不可达,其他值代表路径长度。如果一辆汽车现在要从 x x x y y y ,花费为路径长度之和,再加上除了起点和终点以外所有城市的过路费之和,求最小花费。如果有多条路经符合,则输出字典序最小的路径。
这题就比普通的 F l o y d Floyd Floyd 多了一个数组 p a t h path path ,还要判断当花费与当前最小花费相等时,选择字典序小的情况。具体看代码应该能看懂

代码

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
typedef long long ll;
const ll maxn=110;
const ll INF=0x3f3f3f3f;

int N,x,y;
int dis[maxn][maxn],w[maxn],path[maxn][maxn];

void Floyd()
{
	for(int k=1;k<=N;k++)
	{
		for(int i=1;i<=N;i++)
		{
			for(int j=1;j<=N;j++)
			{
				int temp=dis[i][k]+dis[k][j]+w[k];
				if(temp<dis[i][j])
				{
					dis[i][j]=temp;
					path[i][j]=path[i][k];
				}
				else if(temp==dis[i][j])	//花费与当前最小花费相等时,选择字典序小的那个
				{
					path[i][j]=min(path[i][j],path[i][k]);
				}
			}
		}
	}
}

int main()
{
	while(~scanf("%d",&N))
	{
		if(N==0)	break;
		for(int i=1;i<=N;i++)
		{
			for(int j=1;j<=N;j++)
			{
				scanf("%d",&dis[i][j]);
				if(dis[i][j]==-1)	dis[i][j]=INF;	//不可达
				path[i][j]=j;	//path[i][j]存放i->j这条路上除i外遇到的第一个点
			}
		}
		for(int i=1;i<=N;i++)
			scanf("%d",&w[i]);
		Floyd();
		while(~scanf("%d%d",&x,&y))
		{
			if(x==-1 && y==-1)	break;
			printf("From %d to %d :\n",x,y);
			printf("Path: ");
			int sum=dis[x][y];
			while(x!=y)
			{
				printf("%d-->",x);
				x=path[x][y];
			}
			printf("%d\n",y);
			printf("Total cost : %d\n\n",sum);
		}
	}
	return 0;
}

G - Cow Contest (POJ-3660)

N (1 ≤ N ≤ 100) cows, conveniently numbered 1…N, are participating in a programming contest. As we all know, some cows code better than others. Each cow has a certain constant skill rating that is unique among the competitors.
The contest is conducted in several head-to-head rounds, each between two cows. If cow A has a greater skill level than cow B (1 ≤ A ≤ N; 1 ≤ B ≤ N; A ≠ B), then cow A will always beat cow B.
Farmer John is trying to rank the cows by skill level. Given a list the results of M (1 ≤ M ≤ 4,500) two-cow rounds, determine the number of cows whose ranks can be precisely determined from the results. It is guaranteed that the results of the rounds will not be contradictory.
Input
* Line 1: Two space-separated integers: N and M
* Lines 2…M+1: Each line contains two space-separated integers that describe the competitors and results (the first integer, A, is the winner) of a single round of competition: A and B
Output
* Line 1: A single integer representing the number of cows whose ranks can be determined

Sample InputSample Output
5 5
4 3
4 2
3 2
1 2
2 5
2

分析

题意:共有 N N N 头奶牛参加 M M M 轮比赛,每场比赛奶牛 A A A 总是赢奶牛 B B B 。问 M M M 轮比赛结束后有多少奶牛的排名可以被确定。
这题其实是Floyd求传递闭包的模板题。求完传递闭包后,计算每头奶牛与其他奶牛的关系有几个,如果与其他 N − 1 N-1 N1 头奶牛都有关系(不管是谁赢谁输),就说明它的排名可以被确定。

代码

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
const ll maxn=110;

int N,M,A,B,sum,cnt;
int dis[maxn][maxn];

void Floyd()
{
	for(int k=1;k<=N;k++)
		for(int i=1;i<=N;i++)
			for(int j=1;j<=N;j++)
				dis[i][j]=dis[i][j]||(dis[i][k]&&dis[k][j]);
}

int main()
{
	scanf("%d%d",&N,&M);
	memset(dis,0,sizeof(dis));
	for(int i=0;i<M;i++)
	{
		scanf("%d%d",&A,&B);
		dis[A][B]=1;
	}
	Floyd();
	cnt=0;
	for(int i=1;i<=N;i++)
	{
		sum=0;
		for(int j=1;j<=N;j++)
		{
			if(i==j)	continue;
			if(dis[i][j] || dis[j][i])	sum++;
		}	
		if(sum==N-1)	cnt++;
	}
	printf("%d\n",cnt);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值