40 求调,玄关,内涵思路+丰富注释
查看原帖
40 求调,玄关,内涵思路+丰富注释
1164217
GWOI楼主2024/6/26 17:17

record

思路:使用 prim 从 11 结点开始搜索,能走的就走,用 dd 数组存到达 uu 的最小边,一直找最小边。

#include <bits/stdc++.h>
#define int long long
using namespace std;
using ll = long long;
const int N = 3e6 + 5;

struct O{
	int u, v, z;
	friend bool operator < (O x, O y){
		return x.z > y.z;
	}
};

int n, m;
int a[N], p[N], vis[N];
int d[N];// 表示来到点的花费 

vector<O> g[N];

int get(int x){
	if(x == p[x])	return x;
	return p[x] = get(p[x]);
}

signed main(){
	cin>>n>>m;
	for(int i = 1;i <= n;i++){
		cin>>a[i];
		p[i] = i;
	}
	for(int i = 1;i <= m;i++){
		int u, v, z;
		cin>>u>>v>>z;
		if(a[v] <= a[u]){
			g[u].push_back({u, v, z});// 判断能走的边 
//			cout<<u<<" "<<v<<" "<<z<<"cnm1\n";
		}
		if(a[u] <= a[v]){
			g[v].push_back({v, u, z});
//			cout<<v<<" "<<u<<" "<<z<<"cnm2\n";
		}
	}
	priority_queue<O> q;
	ll sum = 0, ans = 1;
	vis[1] = 1;
	for(auto v : g[1]){
		q.push({v.u, v.v, v.z});// 把 1 结点的临边加进来。 
	}
	while(!q.empty()){// 堆优化的prim 
		O t = q.top();
		q.pop();
//		cout<<t.u<<" "<<t.v<<"t\n";
		if(d[t.v] <= t.z && vis[t.v])	continue;
		/*
		d 数组的定义是要存到达 i 结点的最小边 
		*/ 
//		if(vis[t.v])	continue;
		
		if(!vis[t.v])	ans++;
		
		sum -= d[t.v];
		sum += t.z;// 选择更好的 
		
		d[t.v] = t.z;
		vis[t.v] = 1;
		
//		cout<<d[t.v]<<"\n";
		
		for(auto v : g[t.v]){// 加边 
			if(v.v == t.u)	continue;// 如果搜出来的边是转移过来的边,就continue,不能搜索到父亲
			if(d[v.v] > v.z || !vis[v.v]){// 有更好的边就用,vis[i]表示有没有被使用过 
//				cout<<v.v<<" "<<d[v.v]<<"\n";
				q.push(v);
				continue;
			}
		}
	}
	cout<<ans<<" "<<sum<<"\n";
	return 0;
}
2024/6/26 17:17
加载中...