dijkstral改编

题意:给你包含n个点的连通图,每个点都有一个权值。给定起点和终点。问你起点到终点的最短路条数,并且输出路径最短且权值之和最大的一条路径。

思路:1.如何根据父节点更新子节点。x,y是父子节点。如果从起点s到父节点x的最短路条数为cnt,则从起点到y的最短路条数也为cnt。如果更新某个点最短路条数的时候,发现这个点原来的最短路条数相同的话就要,再原来最短路条数的基础上再加上这次最短路的条数。

2.如何更新从起点到某个点的权值路径的权值之和:如果从起点到父节点x的权值之和为w,则从起点到y的权值之和为w加上y节点的自身的权值之和。

3.L2第一题和L2 26题有一些相同的之处,都是由父节点更新子节点。比如26题父节点的辈分如果是2则子节点的辈分就是在2+1.下面上第一题代码。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<stack>
#include<cmath>
#define inf 0x3f3f3f3f
using namespace std;

int f[1008],ans[1008];//ans数组记录起点到每个点得救援队数量
int w[1008],a[1008][1008];
int v[1008],d[1008],fa[1008];//fa数组记录父亲节点
stack<int> s;
int N,M,S,D,k=1;

void dijkstra()
{
    memset(d,0x3f,sizeof d);
    memset(v,0,sizeof v);
    d[S]=0;
    f[S]=1;
    ans[S]=w[S];
    for(int i=0;i<N;i++)
    {
        int x,m=inf;
        for(int j=0;j<N;j++)
        {
            if(!v[j]&&d[j]<m)
            {
                m=d[j];
                x=j;
            }
        }
        v[x]=1;
        for(int y=0;y<N;y++)
        {
           if(d[y]>d[x]+a[x][y])
           {
               f[y]=f[x];//最短路条数
               d[y]=d[x]+a[x][y];
               fa[y]=x;
            ans[y]=ans[x]+w[y];
           }
           else if(d[y]==d[x]+a[x][y])
           {
               f[y]+=f[x];
               if(ans[y]<ans[x]+w[y])
               {
               fa[y]=x;
               ans[y]=ans[x]+w[y];
            }
           }
        }
    }

}


int main()
{
    scanf("%d%d%d%d",&N,&M,&S,&D);
    for(int i=0;i<N;i++)
    {
    scanf("%d",&w[i]);
    }

    memset(a,0x3f,sizeof a);
    for(int i=0;i<1008;i++)
    fa[i]=-1;
    int x,y,z;
    for(int i=0;i<M;i++)
    {
    cin>>x>>y>>z;
    a[x][y]=z;
    a[y][x]=z;
    dijkstra();
    printf("%d %d\n",f[D],ans[D]);
    s.push(D);
    for(int i=fa[D];i!=-1;i=fa[i])
    {
       s.push(i);
    }

    printf("%d",s.top());
    s.pop();
    while(!s.empty())
    {
       printf(" %d",s.top());
       s.pop();
    }

    return 0;
}

猜你喜欢

转载自www.cnblogs.com/rainyskywx/p/10615639.html