bzoj2753滑雪与时间胶囊(最小生成树)

来源:互联网 发布:java飞机大战代码详解 编辑:程序博客网 时间:2024/05/01 07:20

题意: 景点数要尽可能多,并且在景点数最大的情况下代价最小。
景点数要尽可能大,就是从1能到的所有点都要被遍历(这些点就是要去的景点),dfs即可。
用kruscal算法来做,排序函数简单解释一下
如果两条边的出边的点一样高,代价w越小越优; 否则,出边的点要尽可能高。
因为我们要尽可能先走高的点,才能保证访问的点的个数越多,其次才是权值最小。
边其实是有向边,只能从高处到低处。

/*kruscal*/#include <iostream>#include <stdio.h>#include <algorithm>#include <stdlib.h>#include <stack>#include <vector>#include <string.h>#include <queue>#define msc(X) memset(X,-1,sizeof(X))#define ms(X) memset(X,0,sizeof(X))#define inf 0x7ffffffftypedef long long LL;using namespace std;const int MAXN=1e5+5;const int MAXM=1e6+5;int head[MAXN],h[MAXN],dis[MAXN],pre[MAXN],tot=0,cnt=0;bool vs[MAXN];typedef struct _Edge{    int ato,to,w,next;}Edge;Edge edge[2*MAXM];int cmp(const void *a,const void *b){    Edge *p=(Edge *)a,*q=(Edge *)b;    if(h[p->to]==h[q->to]) return p->w-q->w;    return h[q->to]-h[p->to];}void addedge(int u,int v,int w){    edge[tot].ato=u;    edge[tot].to=v;    edge[tot].next=head[u];    edge[tot].w=w;    head[u]=tot++;}int fnd(int nd){return pre[nd]==nd?nd:(pre[nd]=fnd(pre[nd])); }void dfs(int tn,int fa){    vs[tn]=true;    cnt++;    for(int i=head[tn];i!=-1;i=edge[i].next)    {        int u=edge[i].to;        if(u==fa||vs[u]) continue;        dfs(u,tn);    }}LL kruscal(void){    LL sum=0ll;    int tcn=0;    qsort(edge,tot,sizeof(Edge),cmp);    for(int i=0;i<tot;i++)    {        int fu=fnd(edge[i].ato),fv=fnd(edge[i].to);        if(fu!=fv&&vs[edge[i].ato]&&vs[edge[i].to]){            pre[fu]=fv;            tcn++;            sum+=edge[i].w;            if(tcn==cnt-1) break;        }    }    return sum;}int main(int argc, char const *argv[]){    int n,m;    ms(vs);    msc(head);    scanf("%d %d",&n,&m);    for(int i=1;i<=n;i++) scanf("%d",h+i),pre[i]=i;    while(m--)        {            int u,v,w;            scanf("%d %d %d",&u,&v,&w);            if(h[u]>=h[v]) addedge(u,v,w);            if(h[v]>=h[u]) addedge(v,u,w);        }        dfs(1,-1);        LL res=kruscal();        printf("%d %lld\n",cnt,res );    return 0;}
0 0
原创粉丝点击