题解 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\n",ans1,ans2);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/colazcy/p/11522794.html
今日推荐