看到这道题,发现不会最小生成树,遂昨晚熬夜补了prim算法,今天来写这道题。
看到时间胶囊能回溯,因此确实可以想得到是最小生成树,其实就是最小生成树后求路径长度和最小的问题。这道唯一特别一点的地方就是只能从高处到低处,并且要保证能去的地方最多,所以贪心策略需要加一条:以边终点高的优先选择,保证高度高(能去地方最多)的情况下选择最短路径。
之后,就是prim算法。这里我选择了堆优化。以1为起点,把和1相关的路径全部push进堆里,之后按照贪心策略取出,取到没有访问过的点就如法炮制丢路劲进来。

90分答案:

#include <iostream>
#include <map>
#include <vector>
#include <climits>
#include <algorithm>
#include <random>
#include <cstring>
#include <cstdio>
#include <queue>
#include <map>
#include <set>
#include <bitset>
#define IOS ios_base::sync_with_stdio(0); cin.tie(0);
#define rep(i, a, n) for(register int i = a; i <= n; ++ i)
#define per(i, a, n) for(register int i = n; i >= a; -- i)
#define ONLINE_JUDGE
using namespace std;
typedef long long ll;
const int mod=1e9+7;
template<typename T>void write(T x)
{
    if(x<0)
    {
        putchar('-');
        x=-x;
    }
    if(x>9)
    {
        write(x/10);
    }
    putchar(x%10+'0');
}

template<typename T> void read(T &x)
{
    x = 0;char ch = getchar();ll f = 1;
    while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
    while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);}
ll lcm(ll a,ll b){return a/gcd(a,b)*b;};
ll ksm(ll a,ll n){//看是否要mod
    ll ans=1;
    while(n){
        if(n&1) ans=(ans*a)%mod;
        a=a*a%mod;
        n>>=1;
    }
    return ans%mod;
}
const int maxn=1e5+10;
int n,m;
int h[maxn];
struct Edge{
    int v,k;
    bool operator<(const Edge&b)const{
        return h[v]==h[b.v]?k>b.k:h[v]<h[b.v];
    }
};
vector<Edge> e[maxn];
void add(int u,int v,int k){
    if(h[u]<h[v]) swap(u,v);
    Edge tmp={v,k};
    e[u].push_back(tmp);
    if(h[u]==h[v]){
        e[v].push_back(Edge{u,k});
    }
}
priority_queue<Edge>que;
int vis[maxn];
int cnt;
ll prim(){
    ll res=0;
    int now=1;
    vis[1]=1;
    for(int i=0;i<e[now].size();i++){
        if(vis[e[now][i].v]==0)que.push(e[now][i]);
    }
    cnt++;
    while(!que.empty()){
        Edge a=que.top();
        que.pop();
        if(vis[a.v]==0){
            cnt++;
            now=a.v;
            res+=a.k;
            vis[a.v]=1;
            for(int i=0;i<e[now].size();i++){
                que.push(e[now][i]);
            }
        }
    }
    return res;
}

int main()
{
    #ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    #endif
    //===========================================================
    read(n),read(m);
    rep(i,1,n) read(h[i]);
    rep(i,1,m){
        int u,v,k;
        read(u),read(v),read(k);
        add(u,v,k);
    }
    ll ans=prim();
    write(cnt),putchar(' ');
    write(ans);
    //===========================================================
    return 0;
}

之后再优化一下:如果路径的终点被访问过就不push进来,就过了。

AC代码

#include <iostream>
#include <map>
#include <vector>
#include <climits>
#include <algorithm>
#include <random>
#include <cstring>
#include <cstdio>
#include <queue>
#include <map>
#include <set>
#include <bitset>
#define IOS ios_base::sync_with_stdio(0); cin.tie(0);
#define rep(i, a, n) for(register int i = a; i <= n; ++ i)
#define per(i, a, n) for(register int i = n; i >= a; -- i)
#define ONLINE_JUDGE
using namespace std;
typedef long long ll;
const int mod=1e9+7;
template<typename T>void write(T x)
{
    if(x<0)
    {
        putchar('-');
        x=-x;
    }
    if(x>9)
    {
        write(x/10);
    }
    putchar(x%10+'0');
}

template<typename T> void read(T &x)
{
    x = 0;char ch = getchar();ll f = 1;
    while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
    while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);}
ll lcm(ll a,ll b){return a/gcd(a,b)*b;};
ll ksm(ll a,ll n){//看是否要mod
    ll ans=1;
    while(n){
        if(n&1) ans=(ans*a)%mod;
        a=a*a%mod;
        n>>=1;
    }
    return ans%mod;
}
const int maxn=1e5+10;
int n,m;
int h[maxn];
struct Edge{
    int v,k;
    bool operator<(const Edge&b)const{
        return h[v]==h[b.v]?k>b.k:h[v]<h[b.v];
    }
};
vector<Edge> e[maxn];
void add(int u,int v,int k){
    if(h[u]<h[v]) swap(u,v);
    Edge tmp={v,k};
    e[u].push_back(tmp);
    if(h[u]==h[v]){
        e[v].push_back(Edge{u,k});
    }
}
priority_queue<Edge>que;
int vis[maxn];
int cnt;
inline ll prim(){
    ll res=0;
    int now=1;
    vis[1]=1;
    for(int i=0;i<e[now].size();i++){
        if(vis[e[now][i].v]==0)que.push(e[now][i]);
    }
    cnt++;
    while(!que.empty()){
        Edge a=que.top();
        que.pop();
        if(vis[a.v]==0){
            cnt++;
            now=a.v;
            res+=a.k;
            vis[a.v]=1;
            for(int i=0;i<e[now].size();i++){
                if(vis[e[now][i].v]==0) que.push(e[now][i]);
            }
        }
    }
    return res;
}

int main()
{
    #ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    #endif
    //===========================================================
    read(n),read(m);
    rep(i,1,n) read(h[i]);
    rep(i,1,m){
        int u,v,k;
        read(u),read(v),read(k);
        add(u,v,k);
    }
    ll ans=prim();
    write(cnt),putchar(' ');
    write(ans);
    //===========================================================
    return 0;
}