生成树and最短路 总结篇

总结:

生成树类的题在寒假的时候就开始学了,当时只会照着模板敲分不清 最小生成树和最短路的区别。昨天通过室友(杰哥)的指导,恍然大悟。

                                                                                        下面举例会用到的图

最小生成树(prime算法):

 最小生成树是将 0 1 2 3 4联通的最短路径

代码:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#define N 0x3f3f3f3f
using namespace std;
int map[110][110];
int vis[110];
int s[110];
int n;
void prime()
{
	memset(vis,0,sizeof(vis));
	for(int i=0;i<n;i++)
	{
		s[i]=N;
	 } 
	 s[0]=0; 
	 long long h=0;
	 for(int i=0;i<n;i++)
	 {
	 	long long minn=N;
	 	int u=-1;
	 	for(int j=0;j<n;j++)
	 	{
	 		if(minn>s[j]&&!vis[j])
			{
				minn=s[j];
				u=j;
			}
		}
		h+=minn;
		vis[u]=1;
		for(int j=0;j<n;j++)
		{
			if(s[j]>map[u][j]&&!vis[j])
			{
				s[j]=map[u][j];
			}
		}
	 }
	 cout<<h<<endl;//h就是生成最小生成树的最短路径
}

最短路(Dijkstra算法):

比如: 子节点0 求0到各个节点(1,2,3,4)的最短路径 他们路径都存入 s[] 这个数组里面了。

代码:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#define N 0x3f3f3f3f
using namespace std;
int n,m;
int a[330];
int map[330][330];
int vis[330];
int s[330];
int prime(int x)// 把x当作子节点
{
	
	memset(vis,0,sizeof(vis));
	for(int i=1;i<=n;i++) 
	s[i]=N;
	s[x]=0;
	for(int i=0;i<n;i++)
	{
		int minn=N;
		int u=-1;
		for(int j=1;j<=n;j++)
		{
			
			if(!vis[j]&&minn>s[j])
			{
				minn=s[j];	
				u=j;
			}
			
		}
		vis[u]=1;
		for(int j=1;j<=n;j++)
		{
			if(!vis[j]&&map[u][j]+s[u]< s[j])
			{
				s[j]=map[u][j]+s[u];
			}
		}
	}
	for(int i=1;i<=n;i++)
	{
		cout<<s[i]<<" ";//子节点x到各个子节点的值
	}
	return h;
	
}

一、最大生成树 (如果无法连通成树)

Bad Cowtractors

Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 11136   Accepted: 4688

Description

Bessie has been hired to build a cheap internet network among Farmer John's N (2 <= N <= 1,000) barns that are conveniently numbered 1..N. FJ has already done some surveying, and found M (1 <= M <= 20,000) possible connection routes between pairs of barns. Each possible connection route has an associated cost C (1 <= C <= 100,000). Farmer John wants to spend the least amount on connecting the network; he doesn't even want to pay Bessie. 

Realizing Farmer John will not pay her, Bessie decides to do the worst job possible. She must decide on a set of connections to install so that (i) the total cost of these connections is as large as possible, (ii) all the barns are connected together (so that it is possible to reach any barn from any other barn via a path of installed connections), and (iii) so that there are no cycles among the connections (which Farmer John would easily be able to detect). Conditions (ii) and (iii) ensure that the final set of connections will look like a "tree".

Input

* Line 1: Two space-separated integers: N and M 

* Lines 2..M+1: Each line contains three space-separated integers A, B, and C that describe a connection route between barns A and B of cost C.

Output

* Line 1: A single integer, containing the price of the most expensive tree connecting all the barns. If it is not possible to connect all the barns, output -1.

Sample Input

5 8
1 2 3
1 3 7
2 3 10
2 4 4
2 5 8
3 4 6
3 5 2
4 5 17

Sample Output

42

题意:

贝西承包了联接n个农场间光纤的工程,现在给出m条路线,a  b  c  表示从a农场到b农场连通光纤要c元。 贝西想多赚一点钱,所以尽量选择花费多的路线联接,要保证连接上所有的农场,但是由不能形成环路,那样农场主约翰会知道。 问约翰最多要花费多少钱,不能连通输出-1。 定义一个变量flag 来标记是否存在不连通现象。

代码:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#define N 0x3f3f3f3f
using namespace std;
int map[1100][1100];
int vis[1100];
int s[1100];
int n,m;
long long h=0;
int flag;
void prime()
{
	for(int i=0;i<=n;i++)
	vis[i]=0;
	for(int i=0;i<=n;i++)
	s[i]=-N;
	s[1]=0;
	for(int i=0;i<n;i++)
	{
		int minn=-N;
		int u=-1;
		for(int j=1;j<=n;j++)
		{
			if(!vis[j]&&minn<s[j])
			{
				minn=s[j];
				u=j;
			}
		}
		if(u==-1)//判断是否连通 
		{
			flag=1;
			break;
		}
		h+=minn;
		vis[u]=1;
		for(int j=1;j<=n;j++)
		{
			if(!vis[j]&&map[j][u]>s[j])
			{
				s[j]=map[j][u];
			}
		}
	}
	
}
int main()
{
	while(cin>>n>>m)
	{
	h=0;
	for(int i=0;i<=n;i++)
	{
		for(int j=0;j<=n;j++)
		map[i][j]=-N;
	}
	for(int i=0;i<m;i++)
	{
		int a,b,c;
		cin>>a>>b>>c;
		if(map[a][b]<c)
		{
			map[b][a]=map[a][b]=c;
		}
	}
	flag=0;
	prime();
	if(flag==1)
	cout<<"-1"<<endl;
	else
	cout<<h<<endl;
	}
	return 0;
	
}

二、最小生成树 (记录最大边)

Out of Hay

Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 11580   Accepted: 4515

Description

The cows have run out of hay, a horrible event that must be remedied immediately. Bessie intends to visit the other farms to survey their hay situation. There are N (2 <= N <= 2,000) farms (numbered 1..N); Bessie starts at Farm 1. She'll traverse some or all of the M (1 <= M <= 10,000) two-way roads whose length does not exceed 1,000,000,000 that connect the farms. Some farms may be multiply connected with different length roads. All farms are connected one way or another to Farm 1. 

Bessie is trying to decide how large a waterskin she will need. She knows that she needs one ounce of water for each unit of length of a road. Since she can get more water at each farm, she's only concerned about the length of the longest road. Of course, she plans her route between farms such that she minimizes the amount of water she must carry. 

Help Bessie know the largest amount of water she will ever have to carry: what is the length of longest road she'll have to travel between any two farms, presuming she chooses routes that minimize that number? This means, of course, that she might backtrack over a road in order to minimize the length of the longest road she'll have to traverse.

Input

* Line 1: Two space-separated integers, N and M. 

* Lines 2..1+M: Line i+1 contains three space-separated integers, A_i, B_i, and L_i, describing a road from A_i to B_i of length L_i.

Output

* Line 1: A single integer that is the length of the longest road required to be traversed.

Sample Input

3 3
1 2 23
2 3 1000
1 3 43

Sample Output

43

Hint

OUTPUT DETAILS: 

In order to reach farm 2, Bessie travels along a road of length 23. To reach farm 3, Bessie travels along a road of length 43. With capacity 43, she can travel along these roads provided that she refills her tank to maximum capacity before she starts down a road.

Source

USACO 2005 March Silver

题意:

1号农场的草被牛吃完了,Bessie必须从其他农场运草回来,总共有N个农场,Bessie要去其他所有的农场运草回来,他想要使总路程最短并且路线能连接所有的农场。必须要考虑到路上带的水袋大小。因为水袋大小和路线中距离最长的两个农场之间的路有关,现在Bessie想要求出满足要求的路线中两个农场之间最长的路距离是多少。

思路:

满足要求的路线其实就是最小生成树,路线中两个农场之间最长的路距离就是最小生成树上最长的边。这样用prime求最小生成树的时候,用max求出最小生成树上最长的边。

代码:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#define N 0x3f3f3f3f
using namespace std;
int map[2020][2020];
int vis[2020];
int s[2020];
int n,m,maxl;
void prime()
{
	maxl=0;
	for(int i=1;i<=n;i++)
	{
		vis[i]=0;
	}
	for(int i=1;i<=n;i++)
	{
		s[i]=N;
	}
	s[1]=0;
	for(int i=1;i<=n;i++)
	{
		int minn=N;
		int u=-1;
		for(int j=1;j<=n;j++)
		{
			if(!vis[j]&&minn>s[j])	
			{
				minn=s[j];
				u=j;
			}
		}
		if(minn!=N&&maxl<minn)//记录最大边 
		{
			maxl=minn;
		}
		vis[u]=1;
		for(int j=1;j<=n;j++)
		{
			if(!vis[j]&&map[u][j]<s[j])
			{
				s[j]=map[u][j];
			}
		}
	}
	cout<<maxl<<endl;
}
int main()
{

	while(cin>>n>>m)
	{
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			map[i][j]=map[j][i]=N;
		} 
	}
	for(int i=1;i<=m;i++)
	{
		int a,b,c;
		cin>>a>>b>>c;
		if(map[a][b]>c)
		{
			map[a][b]=map[b][a]=c;
		}
		
	}
	prime();
	}
	
}

三、最短路(求各自节点到各个点的最短路)

Convenient Location

Time limit 1000 ms
Memory limit 131072 kB

Problem Description

明年毕业的A为就业而搬家。就职的公司在若干城市都有办公室,不同天出勤的办公室也不同。所以A在考虑住在哪去各个办公室的时长最短。
这里写图片描述
你为了帮助A,决定去找最方便的居住城市。

城市从0号开始编号,城市之间有道路。不同的道路对应着不同的通勤时间。A 从所住的城市到该城市的办公室的通勤时间认为是 0。此时考虑到所有城市的通勤时间。例如,城市和道路的设置如图所示,A 住在城市 1 的情形下,到不同城市的通勤时间是

到城市 0:80
到城市 1:0
到城市 2:20
到城市 3:70
到城市 4:90

,总和为 260。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

输入道路的数量和所有道路的信息,求出到所有城市的通勤时间最小值和这个最小值对应的城市编号。若有多个城市的总通勤时间都是最小值,输出这些城市编号中的最小值。城市的总数不超过 10,道路的总数不超过 45,所有道路都是双向的,且两个方向的通勤时间是相等的。每个城市到其他任一城市都存在道路。

Input

有多组测试数据,输入由单行 0 终止。每个测试数据格式如下。

n
a1 b1 c1
a2 b2 c2
:
an bn cn
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

第1行给出道路数目 n (1 ≤ n ≤ 45) 。接下来 n 行给出第 i 个道路的信息。 ai, bi (0 ≤ ai, bi ≤ 9) 是第 i 个道路连接的城市的编号,ci (0 ≤ ci ≤ 100) 是这条道路的通勤时间。

Output

对每个测试数据,输出总通勤时间的最小值和对应最小的城市编号,由空格分开,结尾是换行符。

Sample Input

6     
0 1 80
1 2 20
0 2 60
2 3 50
3 4 60
1 4 90
2
0 1 1
1 2 1
0
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

Output for the Sample Input

2 240
1 2
  • 1
  • 2

 直接跑dijkstra 找到最小值

代码:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#define N 0x3f3f3f3f
using namespace std;
int map[15][15];
int vis[15];
int s[15];
int n;
int flag;
int h;
int maxx;
int prime(int x)
{
	h=0;
	for(int i=0;i<=n;i++)
		vis[i]=0;
	for(int i=0;i<=n;i++) 
		s[i]=N;
	s[x]=0;
	for(int i=0;i<=maxx;i++)
	{
		int minn=N;
		int u=-1;
		for(int j=0;j<=maxx;j++)
		{
			if(!vis[j]&&minn>s[j])
			{
				minn=s[j];
				u=j;
			}
		 } 
		vis[u]=1;
		for(int j=0;j<=maxx;j++)
		{	
			if(!vis[j]&&map[u][j]+s[u]<s[j])
			{
				s[j]=map[u][j]+s[u];
			}
		}
	}
	for(int i=0;i<=maxx;i++)
	{
		h+=s[i];
	}
	return h;
}
void bijiao()
{
	int ans=N;
	for(int i=0;i<maxx;i++)
	{
		if(ans>prime(i))
		{
		flag=i;
		ans=prime(i);
		}
	
	}
	cout<<flag<<" "<<ans<<endl;
}
int main()
{
	while(cin>>n)
	{
		if(n==0)
		break;
		maxx=-N;
		flag=0;
		for(int i=0;i<=10;i++)
		{
			for(int j=0;j<=10;j++)
			{
				map[i][j]=N;
			}
		}
		for(int i=0;i<n;i++)
		{
			int a,b,c;
			cin>>a>>b>>c;
			if(a>maxx)
			{
				maxx=a;
			}
			if(b>maxx)
			{
				maxx=b;
			}
			if(map[a][b]>c)
			{
			map[a][b]=map[b][a]=c;
			}
		}
		bijiao();
		
	}
	return 0;
}

Six Degrees of Cowvin Bacon

Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 3131   Accepted: 1455

Description

The cows have been making movies lately, so they are ready to play a variant of the famous game "Six Degrees of Kevin Bacon". 

The game works like this: each cow is considered to be zero degrees of separation (degrees) away from herself. If two distinct cows have been in a movie together, each is considered to be one 'degree' away from the other. If a two cows have never worked together but have both worked with a third cow, they are considered to be two 'degrees' away from each other (counted as: one degree to the cow they've worked with and one more to the other cow). This scales to the general case. 

The N (2 <= N <= 300) cows are interested in figuring out which cow has the smallest average degree of separation from all the other cows. excluding herself of course. The cows have made M (1 <= M <= 10000) movies and it is guaranteed that some relationship path exists between every pair of cows. 

Input

* Line 1: Two space-separated integers: N and M 

* Lines 2..M+1: Each input line contains a set of two or more space-separated integers that describes the cows appearing in a single movie. The first integer is the number of cows participating in the described movie, (e.g., Mi); the subsequent Mi integers tell which cows were. 

Output

* Line 1: A single integer that is 100 times the shortest mean degree of separation of any of the cows. 

Sample Input

4 2
3 1 2 3
2 3 4

Sample Output

100

Hint

[Cow 3 has worked with all the other cows and thus has degrees of separation: 1, 1, and 1 -- a mean of 1.00 .] 

Source

USACO 2003 March Orange

 直接跑dijkstra  这道题难在数据的录入上 并且在输出的时候 应该先 *100 再/(n-1)防止精度损失

代码:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#define N 0x3f3f3f3f
using namespace std;
int n,m;
int a[330];
int map[330][330];
int vis[330];
int s[330];
int h;
int prime(int x)
{
	h=0;
	memset(vis,0,sizeof(vis));
	for(int i=1;i<=n;i++) 
	s[i]=N;
	s[x]=0;
	for(int i=0;i<n;i++)
	{
		int minn=N;
		int u=-1;
		for(int j=1;j<=n;j++)
		{
			
			if(!vis[j]&&minn>s[j])
			{
				minn=s[j];	
				u=j;
			}
			
		}
		vis[u]=1;
		for(int j=1;j<=n;j++)
		{
			if(!vis[j]&&map[u][j]+s[u]< s[j])
			{
				s[j]=map[u][j]+s[u];
			}
		}
	}
	for(int i=1;i<=n;i++)
	{
		
		h+=s[i];
	}
	return h;
	
}
void bijiao()
{
	int ans=N;
	for(int i=1;i<=n;i++)
	{
		ans=min(ans,prime(i));
	}
	ans=(ans*100)/(n-1);
	cout<<ans<<endl; 
}
int main()
{
	while(cin>>n>>m)
	{
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=n;j++)
			{
				map[i][j]=N;
			}
		}
	
		for(int i=0;i<m;i++)
		{
			int t;
			cin>>t;
			cin>>a[1];
			for(int j=2;j<=t;j++)
			{
				
				cin>>a[j];
				for(int e=1;e<j;e++)
				{
					map[a[j]][a[e]]=map[a[e]][a[j]]=1;
				}
			}
		}
		
		bijiao();
	}
	return 0;
}

四、最短路 (单边图)

Silver Cow Party

Time Limit: 2000MS   Memory Limit: 65536K
Total Submissions: 18103   Accepted: 8285

Description

One cow from each of N farms (1 ≤ N ≤ 1000) conveniently numbered 1..N is going to attend the big cow party to be held at farm #X (1 ≤ X ≤ N). A total of M (1 ≤ M ≤ 100,000) unidirectional (one-way roads connects pairs of farms; road i requires Ti (1 ≤ Ti ≤ 100) units of time to traverse.

Each cow must walk to the party and, when the party is over, return to her farm. Each cow is lazy and thus picks an optimal route with the shortest time. A cow's return route might be different from her original route to the party since roads are one-way.

Of all the cows, what is the longest amount of time a cow must spend walking to the party and back?

Input

Line 1: Three space-separated integers, respectively: NM, and X 
Lines 2..M+1: Line i+1 describes road i with three space-separated integers: AiBi, and Ti. The described road runs from farm Ai to farm Bi, requiring Ti time units to traverse.

Output

Line 1: One integer: the maximum of time any one cow must walk.

Sample Input

4 8 2
1 2 4
1 3 2
1 4 7
2 1 1
2 3 5
3 1 2
3 4 4
4 2 3

Sample Output

10

Hint

Cow 4 proceeds directly to the party (3 units) and returns via farms 1 and 3 (7 units), for a total of 10 time units.

题意:

一群牛分别从1~n号农场赶往x号农场参加聚会,农场与农场之间的路时单向的,在n个农场之间有m条路,给出 a ,b , t表示从a号农场到b号农场需要t时间。 每头牛都会选择最短的路,问来回路上(i→x+x→i)花费时间最长的牛花费的时间是多少?

题解:

一眼看过去很简单,先计算x农场到其他农场用的最短时间,在枚举其他农场到x农场的最短时间,记录下最大来回时间即可。的确,不过我们算一算时间复杂度,在枚举其他农场到x农场的最短时间时,最大复杂度为O(n^3)。也就是1000^3,很明显超过了2000ms。所以我们要想办法把枚举过程的复杂度降下来。  这里可以采用置换矩阵,因为是路径时单向的,我们交换 map[i][j] 与 map[j][i] 的值,那么枚举过程就变成了求x到其他农场的最短时间,这里就变成了O(n^2)的算法。

代码:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#define N 0x3f3f3f3f
using namespace std;
int map[1010][1010];
int vis[1010];
int s[1010];
int a1[1010];
int b1[1010];
int n,m,x;
void dijkstra(int w)
{
	for(int i=1;i<=n;i++)
	vis[i]=0;
	for(int i=1;i<=n;i++) 
	s[i]=N;
	s[x]=0;
	for(int i=1;i<=n;i++)
	{
		int minn=N;
		int u=-1;
		for(int j=1;j<=n;j++)
		{
			if(!vis[j]&&minn>s[j])
			{
				minn=s[j];
				u=j;
			}	
		}
		vis[u]=1;
		for(int j=1;j<=n;j++)
		{
			if(!vis[j]&&s[u]+map[u][j]<s[j])
			{
				s[j]=s[u]+map[u][j];
			}
		}
	}
} 
int main()
{
	while(cin>>n>>m>>x)
	{
		for(int i=1;i<=n;++i)
		{
			for(int j=1;j<=n;++j)
			{
				if(i!=j)
					map[i][j]=N;
				else
					map[i][j]=0;
			}
		}
		for(int i=1;i<=m;i++)
		{	
			int a,b,c;
			cin>>a>>b>>c;
			if(map[a][b]>c)
			{
				map[a][b]=c;	
			}
		}
		dijkstra(x);
		for(int i=1;i<=n;i++)
		{
			a1[i]=s[i];//各点到X的距离
		}
		for(int i=1;i<=n;i++)//矩阵转换
		{
			for(int j=i;j<=n;j++)
			{
				int cnt;
				cnt=map[i][j];
				map[i][j]=map[j][i];
				map[j][i]=cnt; 
			}
		}
		dijkstra(x);
		for(int i=1;i<=n;i++)
		{
			b1[i]=s[i];//x到各点的距离
		}
		int ans=0;
		for(int i=1;i<=n;i++)
		{
			
			ans=max(ans,a1[i]+b1[i]);
		}
		cout<<ans<<endl;
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/henucm/article/details/81108733