光明小学的小朋友们要举行一年一度的接力跑大赛了,但是小朋友们却遇到了一个难题:设计接力跑大赛的线路,你能帮助他们完成这项工作么?
光明小学可以抽象成一张有N个节点的图,每两点间都有一条道路相连。光明小学的每个班都有M个学生,所以你要为他们设计出一条恰好经过M条边的路径。
光明小学的小朋友们希望全盘考虑所有的因素,所以你需要把任意两点间经过M条边的最短路径的距离输出出来以供参考。*
你需要设计这样一个函数:
res[][] Solve( N, M, map[][]);
注意:map必然是N * N的二维数组,且map[i][j] == map[j][i],map[i][i] == 0,-1e8 <= map[i][j] <= 1e8。(道路全部是无向边,无自环)2 <= N <= 100, 2 <= M <= 1e6。要求时间复杂度控制在O(N^3*log(M))。
map数组表示了一张稠密图,其中任意两个不同节点i,j间都有一条边,边的长度为map[i][j]。N表示其中的节点数。
你要返回的数组也必然是一个N * N的二维数组,表示从i出发走到j,经过M条边的最短路径
你的路径中应考虑包含重复边的情况。
这个题目要求在30分钟内解决,臣妾做不到的说。先来看看题目解析。
题目解析:该题目要求在M次选择中,计算出i与j之间距离最短的值,是一种动态规划题型,因此我们用动态规划方式解答(C++):
#include <iostream>
using namespace std;
void Solve(int N,int M,int** map,int** res)
{
for(int i=0;i<N;i++)
{
int **E=new int*[N];
for(int j=0;j<N;j++)
E[j]=new int[M]; //建立存放动态结果的矩阵
for(j=0;j<N;j++)
if(i!=j)
E[j][0]=map[i][j];
else
E[j][0]=100000000;
for(int k=1;k<M;k++)
for(j=0;j<N;j++)
E[j][k]=100000000;
for(k=1;k<M;k++)
{
for(j=0;j<N;j++)
{
for(int u=0;u<N;u++)
{
if(u!=j)
{
if(E[j][k]>E[u][k-1]+map[u][j])
E[j][k]=E[u][k-1]+map[u][j];
}
}
}
}
for(j=0;j<N;j++)
res[i][j]=E[j][M-1];
}
};
int main()
{
int N,M; //输入N个结点,M个路径
//建立二维地图
int i,j;
cout<<"请输入结点数N,路径数M和地图Map:";
cin>>N;
cin>>M;
int **map=new int*[N];
int **res=new int*[N];
for(i=0;i<N;i++)
{
map[i]=new int[N];
res[i]=new int[N];
}
for(i=0;i<N;i++)
for(j=0;j<N;j++)
cin>>map[i][j];
for(i=0;i<N;i++)
for(j=0;j<N;j++)
res[i][j]=100000000;
Solve(N,M,map,res);
for(i=0;i<N;i++)
{
for(int j=0;j<N;j++)
cout<<res[i][j]<<" ";
cout<<endl;
}
for(i=0;i<N;i++)
delete[] res[i];
delete[] res;
return 0;
}
以上是动态规划过程,我们从中可以看一下for嵌套的个数,可以发现,该算法的复杂度为O(N^3*M),与要求的不符合,如何做到时间复杂度为O(N^3logM)呢?
我们观察到,我们求取步骤中,其实做了很多的无用功,比如我有4个小朋友,我要求得4段距离总和最小,如果用上面的程序,先求得2段距离最小,然后3段,然后4段,其实在后面基本上都是在原本地图矩阵上查找,地图矩阵i与j之间的距离是1段的距离,当我们计算出2段距离最小时,其实可以将该矩阵作为新的地图,即i与j之间是2段的距离,以此类推,我可以通过4段距离最小矩阵求得8段距离矩阵。此时我们需要用到递归,程序如下:
void Solve(int N,int M,int** map,int** res)
{
int i,j,k;
int a=M/2;
int b=M-a*2;
int **E=new int*[N];
for(i=0;i<N;i++)
E[i]=new int[N];
for(i=0;i<N;i++)
for(j=0;j<N;j++)
E[i][j]=100000000;
if(a==1)
{
for(i=0;i<N;i++)
for(j=0;j<N;j++)
for(k=0;k<N;k++)
if(i!=k&&j!=k&&res[i][j]>map[i][k]+map[k][j])
res[i][j]=map[i][k]+map[k][j];
if(1==b)
{
for(i=0;i<N;i++)
for(j=0;j<N;j++)
for(k=0;k<N;k++)
if(j!=k&&E[i][j]>res[i][k]+map[k][j])
E[i][j]=map[k][j]+res[i][k];
for(i=0;i<N;i++)
for(j=0;j<N;j++)
res[i][j]=E[i][j];
}
for(i=0;i<N;i++)
delete[] E[i];
delete[] E;
return;
}
Solve(N,a,map,res);
for(i=0;i<N;i++)
for(j=0;j<N;j++)
for(k=0;k<N;k++)
if(E[i][j]>res[i][k]+res[k][j])
E[i][j]=res[i][k]+res[k][j];
for(i=0;i<N;i++)
for(j=0;j<N;j++)
{
res[i][j]=E[i][j];
E[i][j]=100000000;
}
if(b==1)
{
for(i=0;i<N;i++)
for(j=0;j<N;j++)
for(k=0;k<N;k++)
if(j!=k&&E[i][j]>res[i][k]+map[k][j])
E[i][j]=res[i][k]+map[k][j];
for(i=0;i<N;i++)
for(j=0;j<N;j++)
res[i][j]=E[i][j];
}
for(i=0;i<N;i++)
delete[] E[i];
delete[] E;
}
int main()
{
int N,M; //输入N个结点,M个路径
//建立二维地图
int i,j;
cout<<"请输入结点数N,路径数M和地图Map:";
cin>>N;
cin>>M;
int **map=new int*[N];
int **res=new int*[N];
for(i=0;i<N;i++)
{
map[i]=new int[N];
res[i]=new int[N];
}
for(i=0;i<N;i++)
for(j=0;j<N;j++)
cin>>map[i][j];
for(i=0;i<N;i++)
for(j=0;j<N;j++)
res[i][j]=100000000;
Solve(N,M,map,res);
for(i=0;i<N;i++)
{
for(int j=0;j<N;j++)
cout<<res[i][j]<<" ";
cout<<endl;
}
for(i=0;i<N;i++)
delete[] res[i];
delete[] res;
return 0;
}
我们在每一层递归中,都传入了地图信息,是因为小朋友数M的个数不一定是2的n次方,若无法整除2,那么就需要地图map的帮助啦,此算法的复杂度可以保证在O(N^3*logM).
有什么问题的话,欢迎留言讨论。
本文为原创文章,欢迎转载,转载请注明出处!
原文地址: https://blog.csdn.net/jiulexiaoyao/article/details/81228934
//复杂度N^3 * logM
void Solve(int N, int M, vector<vector<int>> &map, vector<vector<int>> &R)
{
//动态规划
int i, j, k;
int a = M / 2;
int b = M - a * 2;
vector<int> T(N, (int)1e6);
vector<vector<int>> E(N, T); //动态中间结果
if (a == 1)
{
for (i = 0; i < N; i++)
for (j = 0; j < N; j++)
for (k = 0; k < N; k++)
if (i != k&&j != k&&R[i][j] > map[i][k] + map[k][j])
R[i][j] = map[i][k] + map[k][j];
if (1 == b)
{
for (i = 0; i < N; i++)
for (j = 0; j < N; j++)
for (k = 0; k < N; k++)
if (j != k&&E[i][j] > R[i][k] + map[k][j])
E[i][j] = map[k][j] + R[i][k];
for (i = 0; i < N; i++)
for (j = 0; j < N; j++)
R[i][j] = E[i][j];
}
return;
}
Solve(N, a, map, R);
for (i = 0; i < N; i++)
for (j = 0; j < N; j++)
for (k = 0; k < N; k++)
if (E[i][j] > R[i][k] + R[k][j])
E[i][j] = R[i][k] + R[k][j];
for (i = 0; i < N; i++)
for (j = 0; j < N; j++)
{
R[i][j] = E[i][j];
E[i][j] = (int)1e6;
}
if (b == 1)
{
for (i = 0; i < N; i++)
for (j = 0; j < N; j++)
for (k = 0; k < N; k++)
if (j != k&&E[i][j] > R[i][k] + map[k][j])
E[i][j] = R[i][k] + map[k][j];
for (i = 0; i < N; i++)
for (j = 0; j < N; j++)
R[i][j] = E[i][j];
}
}
int main()
{
int N = 3; //N个结点
int M = 6; //M个路径
//cin >> N;
//cin >> M;
int i, j;
vector<int> T(N, 0);
vector<vector<int>> map(N, T); //建立二维地图
vector<vector<int>> R(N, T); //建立二维表
//输入数据
int Temp[9] = {0,2,3,2,0,1,3,1,0};
for (i = 0; i < N; i++)
{
for (j = 0; j < N; j++)
{
R[i][j] = (int)1e6;
//cin >> map[i][j];
map[i][j] = Temp[i * 3 + j];
}
}
//求解
Solve(N, M, map, R);
//打印
for (i = 0; i < N; i++)
{
for (int j = 0; j < N; j++)
{
cout << R[i][j] << " ";
}
cout << endl;
}
return 0;
}
//复杂度N^3 * M
#include <iostream>
using namespace std;
void Solve(int N, int M, vector<vector<int>>& map, vector<vector<int>>& res)
{
for (int i = 0; i < N; i++)
{
vector<int> T(M, (int)1e6);
vector<vector<int>> E(N, T); //动态中间结果
for (int j = 0; j < N; j++)
if (i != j)
E[j][0] = map[i][j];
else
E[j][0] = 100000000;
for (int k = 1; k < M; k++)
for (int j = 0; j < N; j++)
E[j][k] = 100000000;
for (int k = 1; k < M; k++)
{
for (int j = 0; j < N; j++)
{
for (int u = 0; u < N; u++)
{
if (u != j)
{
if (E[j][k] > E[u][k - 1] + map[u][j])
E[j][k] = E[u][k - 1] + map[u][j];
}
}
}
}
for (int j = 0; j < N; j++)
res[i][j] = E[j][M - 1];
}
};
int main()
{
int N = 3;
int M = 2; //输入N个结点,M个路径
//建立二维地图
int i, j;
vector<int> T(N, 0);
vector<vector<int>> map(N, T); //建立二维地图
vector<vector<int>> R(N, T); //建立二维表
//输入数据
int Temp[9] = {0,2,3,2,0,1,3,1,0};
for (i = 0; i < N; i++)
{
for (j = 0; j < N; j++)
{
R[i][j] = (int)1e6;
//cin >> map[i][j];
map[i][j] = Temp[i * 3 + j];
}
}
Solve(N, M, map, R);
for (i = 0; i < N; i++)
{
for (int j = 0; j < N; j++)
cout << R[i][j] << " ";
cout << endl;
}
return 0;
}
有问题可以留言!