1. 程式人生 > >【NOIP2018普及級別】危險係數

【NOIP2018普及級別】危險係數

時間限制: 1000 ms 空間限制: 131072 KB

題目描述

FJ在一條船上,海上有N(1<=N<=100)島,編號為1..N,現在他的任務是按照一個給定訪問次序A_1,A_2,….A_M去探索這M(2<=M<=10,000)個島嶼,已經知道任意兩個島嶼之間的危險係數,讓你找出一個探索序列,只需滿足你的探索序列包含給定的A_1..A_M這個序列就可以(不一定要連續),使得總的危險係數最小。

輸入

第1行: 兩個數, N 和 M

第 2..M+1行: 第i+1行表示給定的序列中第i個島嶼A_i

第M+2..N+M+1行:每行N個整數,表示島嶼之間的危險係數,對角線上一定是0。

輸出

輸出滿足要求的最小危險係數

樣例輸入

3 4

1

2

1

3

0 5 1

5 0 2

1 2 0

樣例輸出

7

資料範圍限制

提示

【樣例說明】

輸出解釋:我們可以按照1,3,2,3,1,3的順序去探索,滿足了規定了序列是該序列的字序列,危險係數為(1,3)+(3,2)+(2,3)+(3,1)+(1,3)=7。

思路:要使危險係數最小,就要求出多源最短路徑,並且要包含給出的指定路徑,這裡要用到Floyd演算法來做

過程:1.path儲存指定的路徑,mindanger存每條邊的危險係數(邊權)

    2.Floyd求最小生成樹,沿指定路徑走,若某條彎路的危險係數比走一條路還要小,就將小值ik+kj賦予ij

    3.path,path+1也就是每一條邊,此時mindanger中儲存的邊權都是最小的

程式碼:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<vector>
#include<stack>
#include<queue>
#define MAXA 10001
#define INF 0x3f
using namespace std;

int n,m,path[MAXA],mindanger[MAXA][MAXA];
int main()
{
	scanf("%d %d",&n,&m);
	for(int i=1;i<=m;i++)
	    scanf("%d",&path[i]);
	for(int i=1;i<=n;i++)
	    for(int j=1;j<=n;j++)
	    {
	    	scanf("%d",&mindanger[i][j]);
		}
	for(int k=1;k<=n;k++)
	    for(int i=1;i<=n;i++)
	       if(i!=k)
	        for(int j=1;j<=n;j++)
	        if(i!=j && j!=k)
	            if(mindanger[i][k] + mindanger[k][j] < mindanger[i][j])
	               mindanger[i][j] = mindanger[i][k] + mindanger[k][j];
	long long dist = 0;
	for(int i=1;i<m;i++)
	    dist += mindanger[path[i]][path[i+1]];
	printf("%d",dist);
}