首先谈谈这道题的基本思路吧,题目中谈到要将P条道路尽可能的去减少,并保证个点之间是可达的,同时要求其最小时间。
很明显的去告诉我们,用最小生成树算法。
最小生成树算法有两种,
1.克鲁斯卡尔算法 2.prim算法
注意
排序用sort函数。(不要用冒泡排序)。
如果用冒泡排序。会一直显示超时的问题
sort函数(优化后的快速排序)。会根据数据量去选择用何种排序方法(快速排序,或堆排序)
很多向我一样的萌新会去使用冒泡排序,但sort函数既简洁又方便。
技巧:
因为他最后会在每个结点处休息的。所以结点的时间也会去算的。
每个边会走两次(去的时候一次,回来的时候一次,)也就是每条边所花费的时间是
(走边的权的时间*2+去的那个结点安慰奶牛的时间+回来的那个结点安慰奶牛的时间)
由于不管我们怎么走,选取哪些边,从中间走,或从两头走,平均每条边花费的时间都是
上面的
所以我们直接将 边的权=(走边的权的时间*2+去的那个结点安慰奶牛的时间+回来的那个结点安慰奶牛的时间);
最后再进行克鲁斯卡尔算法,求最小生成树的值。
最后值+最小结点,因为有个结点会多走一次(细读题意)。所以我们直接在最小的结点开始走。
(因为一定要连接所有结点),所以否定了这个结点可能走不到的问题。
如果此题
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
struct bian
{
int from;//起点
int to;//终点
int quan;//权值
};
int root (int a[],int x)//寻根算法
{
while(a[x]!=x)
{
x=a[x];
}
return x;
}
bool cmp(bian b1,bian b2)
{
return b1.quan<b2.quan;
}
int main ()
{
int sum=0;//记录所有的时间
int n,p;//结点数与边数
cin>>n;
cin>>p;
int a[n+1];//记录所有点的父亲(双亲表示法)
bian b[p+1];//所有边
int i;
int m[n+1];
int min=10001;
for(i=1;i<=n;i++)
{
cin>>m[i];
if(m[i]<=min)
{
min=m[i];
}
}
for(i=1;i<=p;i++)
{
cin>>b[i].from>>b[i].to>>b[i].quan;
b[i].quan=b[i].quan*2+m[b[i].to]+m[b[i].from];
}
sort(b+1,b+p+1,cmp);
for(i=1;i<=n;i++)
{
a[i]=i;//每个人都是自己的父亲
}
int j;
bian t;
int k=0;//记录kustral算法收纳的边数
int zhong1;
int zhong2;
for(i=1;i<=p;i++)
{
zhong1=root(a,b[i].from);
zhong2=root(a,b[i].to);
if(zhong1!=zhong2)
{
a[zhong1]=zhong2;
sum+=b[i].quan;
k++;
}
if(k==n-1)
{
break;
}
}
cout<<sum+min;
}