floyed算法:dp思想。
动态规划算法的基本步骤:
- 划分阶段:按照问题的时间或空间特征,把问题划分为若干个阶段。这若干个阶段要具备无后向性,即当前状态蕴含了此阶段前的所有历史信息,下一阶段的状态只与当前状态有关。
- 选择状态:将问题发展到各个阶段时所处的各种客观情况用不同的状态表示出来。
- 确定决策并写出状态转移方程:决策即当前阶段到下一个阶段执行的操作,我们通常根据相邻两段的各状态之间的关系来确定决策。
- 写出规划方程(基本方程):只要阶段、状态、决策确定了,基本方程还是比较简单的。注意这里要给出基本方程的边界条件。
OK,动态规划的步骤听起来是不是比较晦涩难懂呢?我们以floyed算法为例看看dynamic programming到底是什么牛鬼蛇神吧!
- 首先,划分阶段哈。我们的map一共包含了n个顶点,根据初始条件,任意两个顶点dis[i][j]的距离要么是相邻距离,要么是∞。设想每经过一个点,dis[i][j]的距离就会更新一次。遍历完所有点,dis[i][j]就会更新n次。于是,我们可以将其划分为n个状态。
- 其次,我们需要确定状态,这个相信大多数人一眼就能看出来,每加入一个点后dis[i][j]就是当前阶段的状态。
- Then,确定决策和状态转移方程。我们的目的是什么呢?当然是让任意两个顶点之间的距离尽可能下。于是,我们可以得到状态转移方程:
dis[i][j] = min(dis[i][j], dis[i][k]+dis[k][j]) - 这里我们的基本方程就是状态转移方程。
标准动态规划的基本框架:
代码ing:
// ConsoleApplication_floyed.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
#include <vector>
#include<algorithm>
#define inf 0x3fffffff
using namespace std;
int main()
{
int N, M, c1, c2;
cin >> N >> M >> c1 >> c2;
vector<vector<int>> vec(N),path(N);
int i, j, k;
for (i = 0; i < N; i++)
{
vec[i].resize(N);
path[i].resize(N);
//dis[i].resize(N);
fill(vec[i].begin(), vec[i].end(), inf);
vec[i][i] = 0;
}
int a, b, c;
for (i = 0; i < M; i++)
{
cin >> a >> b >> c;
vec[a][b] = vec[b][a] = c;
}
for (i = 0; i < N; i++)
{
for (j = 0; j < N; j++)
{
if (vec[i][j] != inf)
{
path[i][j] = j;
}
else
{
path[i][j] = -1;
}
}
}
for (k = 0; k < N; k++)
{
for (i = 0; i < N; i++)
{
for (j = 0; j < N; j++)
{
if (vec[i][j] > vec[i][k] + vec[k][j])
{
vec[i][j] = vec[i][k] + vec[k][j];
path[i][j] = k;
}
}
}
}
cout << vec[c1][c2];
i = c1,j=c2;
cout << endl;
cout << c1;
while (path[i][j] != j)
{
cout << path[i][j];
i = path[i][j];
}
cout << path[i][j];
return 0;
}
测试样例:
5 6 0 2
0 1 1
0 2 2
0 3 1
1 2 1
2 4 1
3 4 1