//最短路径:
//第一行输入 n m (n为节点数,m为边数)
//接下来输入n-1行 s t c(s头,t为尾,c为权值)
//找到最短路径
#include<iostream>
#include<vector>
#define max_size 100//这里需要优化,可计算的数据范围不够大,太大了a数组会有问题
using namespace std;
vector<int> v[max_size];//用于装下一个节点
int a[max_size][max_size];//用于装权值
long long aa[max_size]={0};//用于装从1号节点到当前节点的最优路径权值
vector<int> father[max_size];//用于装当前节点的所有父节点
int num,n;
void create_graph(int n)
{
int i,c,b;
for(i=0;i<n;i++)
{
cin>>c>>b>>a[c][b];
v[c].push_back(b);//装入可去到的节点
father[b].push_back(c);
}
}
void Dijkstra(int n)//传入有向图节点,和从起点到当前节点的权值和
{
int j,k,l;
if(n==num)//不用往上递归特殊处理
{
for(j=0;j<father[n].size();j++)//1.保证其父节点已处理
{
if(father[n][j]==1) continue;
if(aa[father[n][j]]==0)//该父节点还未dp处理过,向上递归,计算其最优路径
{
Dijkstra(father[n][j]);
}
}
aa[n]=a[father[n][0]][n]+aa[father[n][0]];//选num的第一个父节点路线为基线
for(j=1;j<father[n].size();j++)
{
if(a[father[n][j]][n]+aa[father[n][j]]<aa[n]) aa[n]=a[father[n][j]][n]+aa[father[n][j]];
}
}
else if(n==1)//不用往上递归
{
for(j=0;j<v[n].size();j++)
{
Dijkstra(v[n][j]);
}
}
else//图的中间节点
{
for(j=0;j<father[n].size();j++)//1.保证其父节点已处理
{
if(father[n][j]==1) continue;
if(aa[father[n][j]]==0)//该父节点还未dp处理过,向上递归,计算其最优路径
{
Dijkstra(father[n][j]);
}
}
aa[n]=a[father[n][0]][n]+aa[father[n][0]];//选第一个父节点路线为基线
for(j=1;j<father[n].size();j++)//2.计算当前节点最优解
{
if(a[father[n][j]][n]+aa[father[n][j]]<aa[n]) aa[n]=a[father[n][j]][n]+aa[father[n][j]];
}
for(j=0;j<v[n].size();j++)//3.向下遍历
{
if(aa[v[n][j]]!=0) continue;//已计算过其最优解
else
{
Dijkstra(v[n][j]);
}
}
}
}
int main()
{
cin>>num>>n;//num 节点数 ,n 边数
long long res;
create_graph(n);
Dijkstra(1);//狄克斯特拉算法,查找最短路径
cout<<aa[num];
return 0;
}
优化版 dp:
例题:
问题描述
给定一个n个顶点,m条边的有向图(其中某些边权可能为负,但保证没有负环)。请你计算从1号点到其他点的最短路(顶点从1到n编号)。
输入格式
第一行两个整数n, m。
接下来的m行,每行有三个整数u, v, l,表示u到v有一条长度为l的边。
输出格式
共n-1行,第i行表示1号点到i+1号点的最短路。
样例输入
3 3
1 2 -1
2 3 -1
3 1 2
样例输出
-1
-2
数据规模与约定
对于10%的数据,n = 2,m = 2。
对于30%的数据,n <= 5,m <= 10。
对于100%的数据,1 <= n <= 20000,1 <= m <= 200000,-10000 <= l <= 10000,保证从任意顶点都能到达其他所有顶点。
#include<bits/stdc++.h>
#include<vector>
using namespace std;
#define max_size 20010
vector<int> v[max_size];//存子节点
vector<int> father[max_size];//存指向该节点的所有节点
long int res[max_size]={0};//存从起点到该节点的最短路长
vector<int> value[max_size];//存边的权值
int flag[max_size]={0};
int n,m;
void create_graph()
{
int i,a,b,c;
for(i=0;i<m;i++)
{
cin>>a>>b>>c;
v[a].push_back(b);
father[b].push_back(a);
value[b].push_back(c);//权值和父节点在数组中下标的值是一样的,这里是通过索引某个节点的上层节点找最小路径,故权值也通过子节点去索引
}
}
void dp(int num)
{
if(num==1);
else
{
int i;
if(flag[father[num][0]]==0) dp(father[num][0]);
res[num]=res[father[num][0]]+value[num][0];
flag[num]=1;
for(i=0;i<father[num].size();i++)
{
if(flag[father[num][i]]==0)//其父节点未处理过
{
dp(father[num][i]);
}
if(res[father[num][i]]+value[num][i]<res[num]) res[num]=res[father[num][i]]+value[num][i];
}
}
}
void out()
{
int i;
for(i=2;i<=n;i++)
{
if(flag[i]==0) dp(i);//通过最后一点往前找,有可能漏掉一些点
cout<<(long)res[i]<<endl;
}
}
int main()
{
cin>>n>>m;
create_graph();
dp(n);
out();
return 0;
}
内存占用太大