NYOJ-849“路痴”ST【最小生成树】

“路痴“ST

时间限制: 2000 ms  |  内存限制: 65535 KB
难度: 3
描述

         当大一新生ST刚到新的学校的时候对自己的大学校园充满了好奇。但是ST是一个典型的路痴,所以每次出去之后都要想好回到原处的路线(即,从某点A出发,最终将回到A)。现在ST很想好好的参观一下美丽的校园,且ST开始的时候从某处出发选择的路都是双向的。假设经过的路线为V1,V2,....VK,V1,那么必须满足K>2,就是说除了出发点以外至少要经过2个其他不同的校园建筑,而且不能重复经过同一个建筑物。现在ST需要你帮他找一条这样的路线,并且所花费的时间越少越好。

输入
第一行是2个整数N和M(N <= 100, M <= 1000),代表建筑物的个数和道路的条数。
接下来的M行里,每行包括3个整数a,b,c.代表a和b之间有一条通路,并且需要时间花费c分钟(c <= 100)。
输出
对于每个测试实例,如果能找到这样一条路线的话,输出花费的时间的最小值。如果找不到的话,输出"It's impossible."
样例输入
3 31 2 12 3 11 3 13 31 2 11 2 32 3 1
样例输出
3It's impossible.


首先,对于两点之间有重边的情况只考虑权值最小的情况。

接下来,建立最小生成树:


在建立最小生成树的时候要注意记录边是否在树上:


看到这里就应该有几分懂了吧。因为生成了树,树上任意两点连边都会形成环,这就是可以出去再回来的路。这时候我又用了warshall计算了树上的两点间最短路。

最后枚举所有不在树上的边,值因为两点间的树上最短路+所枚举的边权,记录最小值。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <vector>
#define Maxsize 110
#define INF 0x3f3f3f3f
int n,m;
int dist[Maxsize];
int g[Maxsize][Maxsize];
int mincost[Maxsize][Maxsize];
int pre[Maxsize];
bool used[Maxsize][Maxsize];
bool vis[Maxsize];
void init()
{
	memset(g,0x3f,sizeof(g));
	memset(dist,0x3f,sizeof(dist));
	memset(mincost,0x3f,sizeof(mincost));
	memset(used,0,sizeof(used));
	memset(vis,0,sizeof(vis));
	for(int i=0;i<=n;i++)
		mincost[i][i]=0;
}
void addedge(int a,int b,int c)
{
	if(c<g[a][b])
	{
		g[a][b]=c;
		g[b][a]=c;
	}
}
int findmin(int x,int y)
{
	return x>y?y:x;
}
void findtree()
{
	int u;
	dist[1]=0;
	pre[1]=0;
	for(;;)
	{
		int min=INF;
		for(int i=1;i<=n;++i)
			if(min>dist[i]&&!vis[i])
			{
				min=dist[i];
				u=i;
			}
		if(min==INF)
			break;
		vis[u]=1;
		int v=pre[u];
		used[u][v]=used[v][u]=1;
		mincost[u][v]=mincost[v][u]=g[u][v];
		for(v=1;v<=n;v++)
			if(!vis[v]&&dist[v]>g[u][v])
			{
				pre[v]=u;
				dist[v]=g[u][v];
			}
	}
	/*for(int p=1;p<=n;p++)
	{
		for(int q=1;q<=n;q++)
			printf("%d ",used[p][q]);
		printf("\n");
	}*/
}
void findmincostload()
{
	for(int k=1;k<=n;k++)
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
				mincost[i][j]=findmin(mincost[i][j],mincost[i][k]+mincost[k][j]);
	/*for(int p=1;p<=n;p++)
	{
		for(int q=1;q<=n;q++)
			printf("%d ",mincost[p][q]);
		printf("\n");
	}*/

}
int solve()
{
	int res=INF;
	findtree();
	findmincostload();
	for(int i=1;i<=n;i++)
		for(int j=i+1;j<=n;j++)
			if(used[i][j]==0)
				res=findmin(res,mincost[i][j]+g[i][j]);
	return res;
}
int main()
{
	while(~scanf("%d%d",&n,&m))
	{
		init();
		int a,b,c;
		for(int i=0;i<m;++i)
		{
			scanf("%d%d%d",&a,&b,&c);
			addedge(a,b,c);
		}
		int t=solve();
		if(t==INF)
			printf("It's impossible.\n");
		else printf("%d\n",t);
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值