[SCOI2012]滑雪与时间胶囊

遇到一个比较有意思的题目,写出来看看。

如果没有高度相等的点,那么就是一个有向无环图的最小树形图,贪心的让每一个点选入边中权值最小的就可以

加上了高度相等的点后,变成了部分无向的最小树形图,或者说是一个分层后的最小生成树

因为,层与层之间的边都是有向的,而同一层之间的边都是无向的

如何定义层这个概念呢?高度相等的点就是一层

用一种比较巧妙的方式来做最小生成树,就可以避免处理层之间的问题

对边排序时,按照点的高度为第一关键字,边的权值为第二关键字排序

这样上一层的节点都处理完后,再处理下一层的节点,就可以把层与层之间的有向边看成无向边了

对于数据

6 9
8 7 9 6 6 10
1 2 3
1 3 4
1 4 2
1 5 12
2 3 1
4 3 1
4 5 6
3 6 4
5 6 2

  输出

4 11

 

 

 

 

#include<bits/stdc++.h>
using namespace std;
const int N=2e6+10;
int h[N];
struct node
{
	int u,len;
};
vector<node>s[N];
int top=0;
struct EDGE
{
	int u,v,len;
}edge[N];
bool vis[N];
int ans1=1;
void dfs(int u)
{
	vis[u]=true;
	for(int i=0;i<s[u].size();i++)
	{
		edge[++top].u=u;
		edge[top].v=s[u][i].u;
		edge[top].len=s[u][i].len;
		if(!vis[s[u][i].u])
			dfs(s[u][i].u),ans1++;
	}
}
bool cmp(EDGE a,EDGE b)
{
	if(h[a.v]==h[b.v])
		return a.len<b.len;
	return h[a.v]>h[b.v];
}
int fa[N];
int find(int x)
{
	return fa[x]==x? fa[x]:fa[x]=find(fa[x]);
}
signed main()
{
	//	freopen("ski1.in","r",stdin);
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;i++)
		scanf("%d",&h[i]);
	for(int i=1;i<=m;i++)
	{
		int x,y,len;
		scanf("%d%d%d",&x,&y,&len);
		if(h[x]<=h[y])
			s[y].push_back({x,len});
		if(h[x]>=h[y])
			s[x].push_back({y,len});
	}
	dfs(1);
	sort(edge+1,edge+top+1,cmp);
	long long  ans2=0;
	long long sum=0;
	for(int i=1;i<=n;i++)
		fa[i]=i;
	for(int i=1;i<=top;i++)
	{
		int fax=find(edge[i].u),fay=find(edge[i].v);
		if(fax!=fay)
			fa[fax]=fay,sum++,ans2+=edge[i].len;
		if(sum==ans1-1)
			break;
	}
	cout<<ans1<<" "<<ans2<<endl;
}

  

 

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#define maxn 100010
#define maxm 2000010
 
using namespace std;
 
struct yts
{
	int x,y;
	long long z;
}e[maxm];
 
int head[maxn],to[maxm],next[maxm];
bool vis[maxn];
int h[maxn],f[maxn],q[maxn];
int n,m,num,cnt;
long long ans;
 
void addedge(int x,int y,int z)
{
	num++;
	to[num]=y;
	next[num]=head[x];
	head[x]=num;
	e[num]=(yts){x,y,z};
}
 
int find(int x) {return f[x]==x?x:f[x]=find(f[x]);}
 
bool cmp(yts x,yts y)
{
	return h[x.y]>h[y.y] || (h[x.y]==h[y.y] && x.z<y.z);
}
 
void bfs()
{
	int l=0,r=1;
	q[1]=1;
	vis[1]=1;
	cnt=1;
	while (l<r)
	{
		int x=q[++l];
		for (int p=head[x];p;p=next[p])
		  if (!vis[to[p]]) 
		     q[++r]=to[p],vis[to[p]]=1,cnt++;
	}
}
 
int main()
{
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;i++) 
	    scanf("%d",&h[i]);
	for (int i=1;i<=m;i++)
	{
		int x,y;long long z;
		scanf("%d%d%lld",&x,&y,&z);
		if (h[x]>=h[y]) 
		    addedge(x,y,z);
		if (h[y]>=h[x]) 
		    addedge(y,x,z);
	}
	bfs();
	printf("%d ",cnt);
	for (int i=1;i<=n;i++) 
	     f[i]=i;
	sort(e+1,e+num+1,cmp);
	for (int i=1;i<=num;i++)
	{
		int x=e[i].x,y=e[i].y;
		if (!vis[x] || !vis[y])
		     continue;
		int f1=find(x),f2=find(y);
		if (f1!=f2) f[f1]=f2,ans+=e[i].z;
	}
	printf("%lld\n",ans);
	return 0;
}

  

posted @ 2024-04-08 11:50  我微笑不代表我快乐  阅读(16)  评论(0)    收藏  举报