题目描述 Description
a180285 非常喜欢滑雪。他来到一座雪山,这里分布着 M 条供滑行的轨道和 N 个轨道之间的交点(同时也是景点),而且每个景点都有一编号 i(1<=i<=N)和一高度Hi。a180285能从景点i滑到景点j当且仅当存在一条 i和 j之间的边,且 i的高度不小于j。
与其他滑雪爱好者不同,a180285喜欢用最短的滑行路径去访问尽量多的景点。如果仅仅访问一条路径上的景点,他会觉得数量太少。于是 a180285拿出了他随身携带的时间胶囊。
这是一种很神奇的药物,吃下之后可以立即回到上个经过的景点(不用移动也不被认为是a180285 滑行的距离)。请注意,这种神奇的药物是可以连续食用的,即能够回到较长时间之前到过的景点(比如上上个经过的景点和上上上个经过的景点)。
现在,a180285站在1号景点望着山下的目标,心潮澎湃。他十分想知道在不考虑时间胶囊消耗的情况下,以最短滑行距离滑到尽量多的景点的方案(即满足经过景点数最大的前提下使得滑行总距离最小)。你能帮他求出最短距离和景点数吗?
输入描述 Input Description
输入的第一行是两个整数N,M。
接下来1行有N个整数 Hi,分别表示每个景点的高度。
接下来 M 行,表示各个景点之间轨道分布的情况。每行 3 个整数,Ui,Vi,Ki。表示编号为Ui的景点和编号为Vi的景点之间有一条长度为 Ki的轨道。
输出描述 Output Description
输出一行,表示a180285最多能到达多少个景点,以及此时最短的滑行距离总和。
数据范围及提示 Data Size & Hint
对于30%的数据,保证 1<=N<=2000
对于100%的数据,保证 1<=N<=100000
对于所有的数据,保证 1<=M<=1000000,1<=Hi<=1000000000,1<=Ki<=1000000000。
%%%红太阳。
下午想找一道比较好的最小生成树的题,然后红太阳就给我安利了这道。
为什么说是最小生成树呢?
时间胶囊吃下之后可以立即回到上个经过的景点
我们需要遍历这张图的某些节点,我们走到一个节点…吃下胶囊回去了,重复这个过程,直到遍历完所有的节点,假设我们遍历了n个点,最好情况下是走了n-1条边,为了让总路程尽量小,这不就是最小生成树么?
从景点i滑到景点j当且仅当存在一条 i和 j之间的边,且 i的高度不小于j
不 小 于
所以两个点之间距离相等也是可以建边的啊。
对于第一问,我们建好了边以后直接从一号点跑DFS,每跑到一个点,答案就++。
我们一定能到达这个DFS中所到达的点。
那么对于第二问。
再来看看题。
他十分想知道在不考虑时间胶囊消耗的情况下,以最短滑行距离滑到尽量多的景点的方案(即满足经过景点数最大的前提下使得滑行总距离最小)
所以我们首先要保证能滑到尽量多的景点啊。
所以,对于每次到达一个景点,它的高度越高越好。
所以sort里面的cmp函数就要这么写辣。
我们以每条边到达的点按高度大小 从大到小排序,如果两个点高度相等的话,就把权值小的排在前面。
bool cmp(meico a,meico b)
{
if(high[a.to]==high[b.to])
return a.d<b.d;
return high[a.to]>high[b.to];
}
这个题还有个坑点,就是时限和数据范围….看着这一坨零就让人不想做好嘛= =,还有BZOJ上这个题时限是50s是什么意思?
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<queue>
#define maxn 1000000*2+50
using namespace std;
typedef long long ll;
void read(int &a)
{
char c=getchar();
while(c>'9'||c<'0')
c=getchar();
int ans=0;
while(c<='9'&&c>='0')
ans*=10,ans+=c-'0',c=getchar();
a=ans;
return;
}
void readl(ll &a)
{
char c=getchar();
while(c>'9'||c<'0')
c=getchar();
ll ans=0;
while(c<='9'&&c>='0')
ans*=10,ans+=c-'0',c=getchar();
a=ans;
return;
}
struct Edge
{
int f;
int to;
ll d;
int next;
}edge[maxn];
struct meico
{
int f;
int to;
ll d;
}sz[maxn];
ll high[maxn];
int tott;
int head[maxn];
void add1(int f,int t,ll d)
{
edge[++tott]=(Edge){f,t,d,head[f]};
sz[tott]=(meico){f,t,d};
head[f]=tott;
}
int n,m;
bool vis[maxn];
bool cmp(meico a,meico b)
{
if(high[a.to]==high[b.to])
return a.d<b.d;
return high[a.to]>high[b.to];
}
int fa[maxn];
int find(int x)
{
return fa[x]==x?x:fa[x]=find(fa[x]);
}
int ans1;
void dfs(int f,int t)
{
vis[t]=1;
ans1++;
for(int i=head[t];i;i=edge[i].next)
{
Edge e=edge[i];
if(!vis[e.to])
dfs(t,e.to);
}
}
void K()
{
sort(sz+1,sz+tott+1,cmp);
int tot=0;
ll ans=0;
for(int i=1;i<=tott;i++)
{
meico m=sz[i];
if(!vis[m.f]||!vis[m.to])
continue;
int x=find(m.f);
int y=find(m.to);
if(x!=y)
{
fa[x]=y;
ans+=m.d;
}
}
printf("%lld",ans);
}
int main()
{
read(n),read(m);
for(int i=1;i<=n;i++)
readl(high[i]),fa[i]=i;
for(int i=1;i<=m;i++)
{
int a,b;
ll c;
read(a),read(b),readl(c);
if(high[a]>=high[b])
add1(a,b,c);
if(high[a]<=high[b])
add1(b,a,c);
}
dfs(1000005,1);
printf("%d ",ans1);
K();
return 0;
}