滑雪与时间胶囊

来源:互联网 发布:linux常用命令gcc 编辑:程序博客网 时间:2024/04/19 21:18

题目大意:

一个孩子去滑雪,他想要用最短距离访问最多景点,题目会给出M条路径和N个景点。景点是路径的交点。这个孩子还有时间胶囊,时间胶囊可以让他直接转移到上次访问过的景点,问:他从第一个点开始滑,在访问最多景点的条件下,最短路径是多少?


这道题不能用 prim 算法去做,原来 prim 是有缺陷的,它针对无向图是正确的,并不能保证有向图一定正确。

比如说

3 3

3 2 1

1 2 7

2 3 1

1 3 5

这样的话用prim得出的结论是5+7=12,而实际上,我们可以先到2号点,再从二号到3号。这样答案就是最优解7+1=8;故若采用最小生成树方法时,便应当考虑kruskal算法。

思路是这样的:
先用bfs()遍历完所有可能遍历到的节点,标记能遍历到的,然后对原式进行排序先从去的高处向下排,再按路径长度按从小到大排序,然后就套用Kruskal模板。
为什么要用bfs()先遍历呢?这是因为或许会出现一种情况:一条边的两端不可以被遍历到,但是这条边很短,且终点很高,容易被Kruskal添加进去,故要避免这种情况。
先用bfs()遍历,能被遍历的节点被标记为need=true;添加边时应当使两端顶点need都为true;

#include<list>#include<queue>#include<iostream>#include<algorithm>#include<cstring>#include<cstdio>#include<vector>using namespace std;struct place//景点结点{    int from;    int to;    int disten;};struct rec//辅助bfs(){    int to;    int weight;    rec* next;};rec* vec[100001];const int inf = 0x3f3f3f3f;bool need[100001];bool used[100001];int hei[100001];place p[2000001];int parent[100001];int n, m;int coun;//统计遍历的边数 [0,coun)int reach;void addedge(int f,int t,int w){    p[coun++]=place{f,t,w};    rec *l=new rec;    l->to=t;    l->weight=w;    l->next=vec[f];    vec[f]=l;}bool com(place a, place b){    if (hei[a.to] == hei[b.to])        return a.disten < b.disten;    else        return hei[a.to]>hei[b.to];}void bfs()  //遍历所有可能到达的结点{    queue<int>q;    q.push(1);    need[1]=true;    while(!q.empty())    {        int t=q.front();        q.pop();           if(++reach==n)  return ;        for( rec* it=vec[t]; it; it=it->next)        {            if(need[it->to]==false)            {                need[it->to]=true;                q.push(it->to);            }        }    }}int getpare(int a)//parent【a】=getparent(parent【a】),这句话会很好的提高效率,加快访问到根节点的时间{    return (parent[a] == a) ? a : parent[a]=getpare(parent[a]);}void  kruskal()//最小生成树{    long long dis = 0;    sort(p, p + coun, com);//排序的原则是去的最高点优先,然后是路径长度    for (int q = 1; q <= n; ++q)        parent[q] = q;    for (int i = 0; i<coun; ++i)    {        if (need[p[i].from]&&need[p[i].to])        {            int p1 = getpare(p[i].from);            int p2 = getpare(p[i].to);            if (p1 != p2)            {                dis += p[i].disten;                parent[getpare(p[i].from)]=getpare(p[i].to);            }        }    }    printf("%lld\n",dis);}int main(){    scanf("%d%d", &n, &m);    for (int i = 1; i <= n; ++i)  scanf("%d", &hei[i]);    reach = 0;    coun = 0;    int  f, t, w;    for (int i = 1; i <= m; ++i)    {        scanf("%d%d%d", &f, &t, &w);        if (hei[f] >= hei[t])        {            addedge(f,t,w);        }        if(hei[f]<=hei[t])        {            addedge(t,f,w);        }    }    bfs();    printf("%d ",reach);    kruskal();}


0 0
原创粉丝点击