输入样例
6 7
3 1 4 1 5 9
1 2 7
1 3 11
2 3 13
3 4 1
3 6 19
4 5 20
5 6 1
输出样例
5
我们需要走遍整张图,故求最小生成树即可,想复杂了。
因为我们需要拿完所有的金币且开局带的金币最少,显然只需要过路费对我们的限制最小,找到过路费最少且能走完所有的城市的路就ok了,用过路费当做两个城市的距离求最小生成树即可。
巧妙点在于如何存需要过路费的最大值,如下
#include<bits/stdc++.h>
using namespace std;
int city[100005];
int n,m;
int getMoney[100005];
int needMoney[100005];
struct road{
int x;
int y;
int need;
}Roads[100005];
bool cmp( road a , road b ){
return a.need<b.need;
}
int getF( int a ){
return a==city[a]?a:city[a]=getF(city[a]); //并查集并且进行路径压缩。
}
int main(){
cin>>n>>m;//n个城市,m条路
for ( int k = 1 ; k <= n ; ++k ){
scanf("%d",&getMoney[k]);
city[k] = k; //进过第N个城市获得的金币数,初始化并查集
}
for ( int k = 0 ; k < m ; ++k ) scanf("%d%d%d",&Roads[k].x,&Roads[k].y,&Roads[k].need); //输入所有路;
sort( Roads , Roads + m , cmp );
for ( int k = 0 ; k < m ; ++k ){
int x = getF( Roads[k].x );
int y = getF( Roads[k].y );
if ( x == y ) continue; //成环
needMoney[x] = max( needMoney[x] , Roads[k].need - getMoney[x] );
needMoney[y] = max( needMoney[y] , Roads[k].need - getMoney[y] );
if ( needMoney[x] > needMoney[y] )
swap( x , y );
//如果从x走到y比y走到x需要初始金额更多,那么选择小的一个
//故我们交换xy,这时从x->y需要的金额较少
getMoney[x] += getMoney[y];
//此时你走到x会获得的金币会累加,同时你need的Money也存入了x
city[y] = x; //连接两条路
//注.这句话与 city[x] = y 不等价
//因为你能获取的钱累加到了x上,但事实上你在x与y两点获取的钱是一样的,所以我们用city[y]=x指向
//如果用 city[x] = y的话,那么你想取在y出得到的最多的钱也就变成了 needMoney[ getF( y ) ] = needMoney[y] != needMoney[x];
}
cout<<needMoney[ getF(1) ]<<endl;
//最终整个图被连成了一个树,所以getF(x) x可以为 1-n的任何数
}