题意:给你包含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 ",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; }