【程式設計測試題】阿里巴巴2019年提前批程式設計題
光明小學的小朋友們要舉行一年一度的接力跑大賽了,但是小朋友們卻遇到了一個難題:設計接力跑大賽的線路,你能幫助他們完成這項工作麼?
光明小學可以抽象成一張有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;
}
有問題可以留言!
相關文章
- 【測繪程式設計試題集】 試題04 最短路徑計算程式設計
- 【程式設計測試題】頭條校招程式設計
- 【測繪程式設計試題集】 試題02 矩陣卷積計算程式設計矩陣卷積
- 【測繪程式設計試題集】 試題01 計程車軌跡資料計算程式設計
- 程式設計師進階之路之面試題與筆試題集錦(三)線上程式設計題程式設計師面試題筆試
- 【程式設計測試題】遊戲任務標記程式設計遊戲
- 【程式設計測試題】素數對、不要二、求和程式設計
- JS程式設計題JS程式設計
- 程式設計題求解程式設計
- C程式設計題C程式程式設計
- go程式設計題Go程式設計
- 【測繪程式設計試題集】 試題09 反距離加權插值程式設計
- 程式碼設計問題
- 程式設計題目解析程式設計
- 計科190405程式設計題解程式設計
- 程式設計師50+Java面試題程式設計師Java面試題
- 智力題(程式設計師面試經典)程式設計師面試
- Java程式設計師面試題及解答Java程式設計師面試題
- JAVA程式設計師面試題庫分享Java程式設計師面試題
- Java程式設計__Chap3 面對物件__程式設計題Java程式設計物件
- 面試題:web程式設計技術考試題庫(含答案)面試題Web程式設計
- JS中的程式設計題JS程式設計
- c語言程式設計題C語言程式設計
- 程式設計題-兩數相加程式設計
- 順序程式設計習題程式設計
- Linux網路程式設計常見面試題Linux程式設計面試題
- VUE的面試題分享-好程式設計師Vue面試題程式設計師
- 程式設計師面試題!親身經歷!程式設計師面試題
- Java程式設計師面試常見問題Java程式設計師面試
- 【測繪程式設計試題集】 試題06 軌跡資料壓縮演算法程式設計演算法
- CCUT程式設計能力測試---前言程式設計
- 好程式設計師分享:Java面試題常見問題程式設計師Java面試題
- 物件導向程式設計-java語言 第二週程式設計題物件程式設計Java
- Java初中級程式設計師面試題寶典Java程式設計師面試題
- 大資料面試題整理-好程式設計師大資料面試題程式設計師
- Python期中考試程式設計題詳解-2Python程式設計
- 全職爸爸,是程式設計師的加試題程式設計師
- 程式設計面試問題真的越難越好嗎?No!程式設計面試