题解 P2573 【[SCOI2012]滑雪】

题目链接

Solution [SCOI2012]滑雪

题目大意:给你一个图,每个点有一个高度,你只能从一个点走向高度不大于它的点,求在可以走的点最多的限制下的最小权值和

最小生成树,贪心


分析:如果不考虑高度限制,这题实质上是一个最小生成树,关键在于考虑上高度限制

既然要使得走到的点最多,显然我们优先从一个点走向它可以走的点集里面高度最高的点,这样可以使得答案最优.然后在这个基础上使得权值之和最小

可以用类似(Prim)算法求解,朴素(Prim)从可以扩展的点集(V)里面选择离生成树最近的点扩展,这里选择高度最大的点扩展,如果高度一样选择离生成树最近的即可

貌似还可以用(Kruskal?),不过感觉不是很直观的样子(主要是(TCL))

代码:

#include <cstdio>
#include <cstring>
#include <cctype>
#include <queue>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 100,maxm = 2e6 + 100;
inline int read(){
	int x = 0;char c = getchar();
	while(!isdigit(c))c = getchar();
	while(isdigit(c))x = x * 10 + c - '0',c = getchar();
	return x;
}
struct Edge{
	int from,to,dist;
}Edges[maxm];
int head[maxn],nxt[maxm],n,m;
inline void addedge(int from,int to,int dist){
	static int tot;
	Edges[++tot] = Edge{from,to,dist};
	nxt[tot] = head[from];
	head[from] = tot;
}
int high[maxn];
ll ans1,ans2;
int dis[maxn],vis[maxn];
struct Point{
	int u,high,dis;
	bool operator < (const Point &rhs)const{
		return (high == rhs.high) ? (dis > rhs.dis) : (high < rhs.high);
	}
};
priority_queue<Point> Q;
int main(){
	n = read(),m = read();
	for(int i = 1;i <= n;i++)high[i] = read();
	for(int u,v,d,i = 1;i <= m;i++)
		u = read(),v = read(),d = read(),addedge(u,v,d),addedge(v,u,d);
	memset(dis,0x3f,sizeof(dis));
	dis[1] = 0;Q.push(Point{1,high[1],dis[1]});
	while(!Q.empty()){
		Point p = Q.top();Q.pop();
		int u = p.u;
		if(vis[u])continue;
		vis[u] = 1;
		ans1++;
		ans2 += dis[u];
		for(int i = head[u];i;i = nxt[i]){
			int v = Edges[i].to;
			if(vis[v])continue;
			if(high[u] < high[v])continue;
			if(Edges[i].dist < dis[v]){
				dis[v] = Edges[i].dist;
				Q.push(Point{v,high[v],dis[v]});
			}
		}
	}
	printf("%lld %lld
",ans1,ans2);
	return 0;
}
原文地址:https://www.cnblogs.com/colazcy/p/11522794.html