BZOJ2753: [SCOI2012]滑雪与时间胶囊
【传送门:BZOJ2753】
简要题意:
有n个景点,有m条边,每条边有长度,每个景点有一定的高度,i能走向j当且仅当i与j之间有边,而且i的高度大于等于j的高度,求从1出发,在遍历最多景点数的情况下,求出景点数和最短路径长度
题解:
开始还以为直接宽搜过的水题
结果。。
咳咳,讲题解讲题解
首先用v[i]能否从1点走到i点,然后对于一条边x,y,只要有一个点的v为false时,这条边就是废的
然后用最小生成树来做
那么怎么处理每条边的优先级呢?
首先我们按y的高度为第一优先级从大到小排,然后以长度为第二优先级从小到大排
为什么?
因为如果x能连向y,那么就说明h[x]>=h[y],所以,这样子做就能够保证走的一直是一条路径
然后我们还要加一条0到1的边,长度为0,且把h[0]弄成无限大
这样子就能够保证从1点开始走了
看这数据范围也是要加long long的
参考代码:
#include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; typedef long long LL; int h[1100000]; struct node { int x,y,next; LL d; }a[4100000];int last[1100000],len; void ins(int x,int y,LL d) { len++; a[len].x=x;a[len].y=y;a[len].d=d; a[len].next=last[x];last[x]=len; } bool v[1100000]; void dfs(int x) { for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(v[y]==false) { v[y]=true; dfs(y); } } } int fa[1100000]; bool cmp(node n1,node n2) { if(h[n1.y]>h[n2.y]) return true; if(h[n1.y]<h[n2.y]) return false; if(n1.d<n2.d) return true; if(n1.d>n2.d) return false; } int findfa(int x) { if(fa[x]!=x) fa[x]=findfa(fa[x]); return fa[x]; } int main() { int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&h[i]); len=0;memset(last,0,sizeof(last)); for(int i=1;i<=m;i++) { int x,y;LL d; scanf("%d%d%lld",&x,&y,&d); if(h[x]>=h[y]) ins(x,y,d); if(h[x]<=h[y]) ins(y,x,d); } memset(v,false,sizeof(v)); v[0]=v[1]=true; dfs(1); h[0]=999999999; ins(0,1,0); for(int i=0;i<=n;i++) fa[i]=i; sort(a+1,a+len+1,cmp); LL ans=0;int t=0; for(int i=1;i<=len;i++) { int x=a[i].x,y=a[i].y; if(v[x]==false||v[y]==false) continue; int fx=findfa(x),fy=findfa(y); if(fx!=fy) { fa[fy]=fx; ans+=a[i].d; t++; } } printf("%d %lld\n",t,ans); return 0; }
渺渺时空,茫茫人海,与君相遇,幸甚幸甚