题目链接:https://codeforces.com/contest/1204/problem/C
思路:先用floyd求出任意两点间最短路,然后逐一对每个点进行判断,设上一个必须出现在子序列中的点为cnt,若满足g[ cnt ] [ p[i+1] ] < g[ cnt ] [ p[i] ] + g[ p [ i ] ] [ p [ i + 1 ] ] , 说明从cnt到p[i+1]按最短路走不经过p[i], 所以p[i]必须出现。然后把p[i]加入序列,即
cnt = p[i] .
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 205;
const int INF = 0x7f7f7f7f;
const int N = 1e6 + 5;
int g[maxn][maxn];
int p[N];
bool f[N];
int main() {
int n , m;
ios::sync_with_stdio(0);
cin >> n;
for(int i = 1 ;i <= n ; i++) {
for(int j = 1 ; j <= n ; j++) {
char t;
cin >> t;
g[i][j] = t - '0';
if(!g[i][j])g[i][j] = INF;
}
}
for(int k = 1 ; k <= n ; k++) {
for(int i = 1 ; i <= n ; i++) {
for(int j = 1 ; j <= n ; j++) {
if(g[i][k] < INF && g[k][j] < INF)
g[i][j] = min(g[i][k] + g[k][j] , g[i][j]);
}
}
}
cin >> m;
int t = m;
for(int i = 1 ; i <= m ; i++)cin >> p[i];
int cnt = p[1];
for(int i = 2 ; i <= m - 1 ; i++) {
if(g[cnt][p[i]] + g[p[i]][p[i + 1]] <= g[cnt][p[i + 1]] && cnt != p[i+1]) {
f[i] = 1;
t--;
}
else cnt = p[i];
}
cout << t << "\n";
for(int i = 1 ; i <= m ; i++) {
if(f[i])continue;
cout << p[i] << " ";
}
}