码迷,mamicode.com
首页 > 其他好文 > 详细

BZOJ 2753 滑雪与时间胶囊(最短路-克鲁斯卡尔)

时间:2014-06-21 14:26:30      阅读:208      评论:0      收藏:0      [点我收藏+]

标签:style   class   blog   http   tar   ext   

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2753

题意:一个n个点m条边的带权无向图,每个点有一个高度值h。某个从1号点开始遍历,每次走的边u到v,必须满足h[u]>=h[v]。已知从当前点回到曾经遍历过的任意一个点是不需要走路的。求最多可以遍历多少个点?遍历这些点走的最小路程是多少?

思路:只记录h[u]>=h[v]的 边,因为其他边是无用的,这样其实是个有向图。首先从1BFS一次可以得到多少个点可以到达。然后将边排序,对于边<u,v,w>按照 h[v]降序排序,然后h[v]相等的按照w升序。这样用克鲁斯卡尔并查集一下就行。

 

struct node
{
    int u,v,w,next;
};


node edges[N<<1];
int head[N],e;


void Add(int u,int v,int w)
{
    edges[e].u=u;
    edges[e].v=v;
    edges[e].w=w;
    edges[e].next=head[u];
    head[u]=e++;
}




int a[N];
i64 dis[N];
int n,m,visit[N];


int cmp(node p,node q)
{
    return a[p.v]>a[q.v]||a[p.v]==a[q.v]&&p.w<q.w;
}


int f[N];


int get(int x)
{
    if(f[x]!=x) f[x]=get(f[x]);
    return f[x];
}


i64 cal()
{
    sort(edges,edges+e,cmp);
    int i;
    FOR1(i,n) f[i]=i;
    int x,y,u,v;
    i64 ans=0;
    FOR0(i,e)
    {
        u=edges[i].u;
        v=edges[i].v;
        if(!visit[u]||!visit[v]) continue;
        x=get(u);
        y=get(v);
        if(x!=y) f[x]=y,ans+=edges[i].w;
    }
    return ans;
}


int main()
{
    RD(n,m);
    int i;
    FOR1(i,n) RD(a[i]);
    int x,y,w;
    clr(head,-1);
    FOR1(i,m)
    {
        RD(x,y,w);
        if(a[x]>=a[y]) Add(x,y,w);
        if(a[y]>=a[x]) Add(y,x,w);
    }
    queue<int> Q;
    int cnt=0;
    Q.push(1);
    visit[1]=1;
    while(!Q.empty())
    {
        x=Q.front();
        Q.pop();
        cnt++;
        for(i=head[x];i!=-1;i=edges[i].next)
        {
            y=edges[i].v;
            if(!visit[y]) visit[y]=1,Q.push(y);
        }
    }
    printf("%d %lld\n",cnt,cal());
}

 

 

 

BZOJ 2753 滑雪与时间胶囊(最短路-克鲁斯卡尔),布布扣,bubuko.com

BZOJ 2753 滑雪与时间胶囊(最短路-克鲁斯卡尔)

标签:style   class   blog   http   tar   ext   

原文地址:http://www.cnblogs.com/jianglangcaijin/p/3799578.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!