题目描述
a180285非常喜欢滑雪。他来到一座雪山,这里分布着M条供滑行的轨道和N个轨道之间的交点(同时也是景点),而且每个景点都有一编号
i
(
1
≤
i
≤
N
)
i(1 \le i \le N)
i(1≤i≤N)和一高度H_i。a180285能从景点ii滑到景点jj当且仅当存在一条i和j之间的边,且i的高度不小于j。 与其他滑雪爱好者不同,a180285喜欢用最短的滑行路径去访问尽量多的景点。如果仅仅访问一条路径上的景点,他会觉得数量太少。于是a180285拿出了他随身携带的时间胶囊。这是一种很神奇的药物,吃下之后可以立即回到上个经过的景点(不用移动也不被认为是a180285 滑行的距离)。请注意,这种神奇的药物是可以连续食用的,即能够回到较长时间之前到过的景点(比如上上个经过的景点和上上上个经过的景点)。 现在,a180285站在11号景点望着山下的目标,心潮澎湃。他十分想知道在不考虑时间胶囊消耗的情况下,以最短滑行距离滑到尽量多的景点的方案(即满足经过景点数最大的前提下使得滑行总距离最小)。你能帮他求出最短距离和景点数吗?
思路
- 先按高度建图,再dfs或bfs搜出所有可以到达的点
- 把这些合法的边建一个新图,把他当做一个分层的图,同一高度就是一层,这样跑最小生成树就可以了
code
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
inline int read(){
char ch=' ';int f=1;int x=0;
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*f;
}
const int N=1e5+100;
const int M=2e6+100;
int h[N];
struct node
{
int v,nxt;
int w;
}edge[M];
int head[N],cnt;
void add(int u,int v,int w)
{
cnt++;
edge[cnt].v=v;
edge[cnt].w=w;
edge[cnt].nxt=head[u];
head[u]=cnt;
}
int cc;
struct data
{
int h;int w;
int a,b;
}d[M];
void push(int a,int b,int w)
{
cc++;
d[cc].a=a;d[cc].b=b;
d[cc].w=w;
d[cc].h=min(h[a],h[b]);
}
bool cmp(data x,data y)
{
if(x.h==y.h) return x.w<y.w;
return x.h>y.h;
}
bool vis[N];
int sum;
int q[N],he,ta;
void bfs()// 当然这里也可以用dfs来写,稍微快一点点
{
he=ta=1;
q[1]=1;vis[1]=true;sum++;
while(he<=ta)
{
int u=q[he];
for(int i=head[u];i;i=edge[i].nxt)
{
int v=edge[i].v;
push(u,v,edge[i].w);
if(!vis[v])
{
q[++ta]=v;
sum++;
vis[v]=true;
}
}
he++;
}
}
int f[N];
int getf(int p)
{
if(f[p]==p)
return p;
return f[p]=getf(f[p]);
}
int main()
{
int n,m;
n=read();m=read();
for(int i=1;i<=n;i++)
h[i]=read();
int u,v,w;
for(int i=1;i<=m;i++)
{
u=read();v=read();w=read();
if(h[u]>=h[v]) add(u,v,w);
if(h[v]>=h[u]) add(v,u,w);
}
bfs();
sort(d+1,d+1+cc,cmp);
long long ans=0;
for(int i=1;i<=n;i++) f[i]=i;
for(int i=1;i<=cc;i++)
{
int f1=getf(d[i].a);
int f2=getf(d[i].b);
if(f1!=f2)
{
f[f1]=f2;
ans+=d[i].w;
n--;
}
if(n==1) break;
}
cout<<sum<<' '<<ans<<endl;
return 0;
}
//dfs版
void dfs(int u)
{
if(vis[u]) return ;
vis[u]=true;sum++;
for(int i=head[u];i;i=edge[i].nxt)
{
int v=edge[i].v;
int w=edge[i].w;
push(u,v,w);
dfs(v);
}
}