CF1204C Anna, Svyatoslav and Maps 题解
题目链接:CF1204C Anna, Svyatoslav and Maps
题意:
对于 \(n(n \le 100)\) 个点有向无环图,给出一个由 \(m(m \le 10^6)\) 个点组成的的路径 \(p\)(不保证是简单路径,但保证对于 \(1 \le i < m,p_i\) 与 \(p_{i+1}\) 之间有边), 要求从 \(p\) 中选出一个最短的子序列 \(v\)(假设长度为 \(k\) ),满足 \(v_1=p_1,v_k=p_m\) ,并且 \(p\) 是按顺序经过 \(v\) 的最短路径之一。
输入格式:
The first line contains a single integer \(n\) ( \(2 \le n \le 100\) ) — the number of vertexes in a graph.
The next \(n\) lines define the graph by an adjacency matrix: the \(j\) -th character in the \(i\) -st line is equal to \(1\) if there is an arc from vertex \(i\) to the vertex \(j\) else it is equal to \(0\) . It is guaranteed that the graph doesn't contain loops.
The next line contains a single integer \(m\) ( \(2 \le m \le 10^6\) ) — the number of vertexes in the path.
The next line contains \(m\) integers \(p_1, p_2, \ldots, p_m\) ( \(1 \le p_i \le n\) ) — the sequence of vertexes in the path. It is guaranteed that for any \(1 \leq i < m\) there is an arc from \(p_i\) to \(p_{i+1}\) .
输出格式:
In the first line output a single integer \(k\) ( \(2 \leq k \leq m\) ) — the length of the shortest good subsequence. In the second line output \(k\) integers \(v_1,\ldots,v_k\) ( \(1 \leq v_i \leq n\) ) — the vertexes in the subsequence. If there are multiple shortest subsequences, print any. Any two consecutive numbers should be distinct.
题目的意思有点鬼畜,其实就是问你这个最短路径构成的路线中有多少个点是可以删掉的。
注意到如果 \(d(i,j) > d(i,k) + d(k,j)\) ,则点 \(k\) 就不能删除。
也就是说在 \(i,j\) 最短路径上的非 \(i,j\) 点可以删除。
注意到 \(n\) 非常小,所以我们可以用 \(\mathtt{Floyd}\) 预处理一下最短路,然后扫一遍就好了。
时间复杂度 \(\mathcal{O}(n^3 + |p|)\)
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
void up(int &x,int y) { x < y ? x = y : 0; }
void down(int &x,int y) { x > y ? x = y : 0; }
#define N ((int)(115))
#define M ((int)(1e6+14))
char s[N],vis[N];
int n,m,g[N][N],d[N][N],p[M];
vector<int> vec;
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
// freopen("check.in","r",stdin);
// freopen("check.out","w",stdout);
cin >> n;
for(int i=1; i<=n; i++)
{
cin >> (s+1);
for(int j=1; j<=n; j++)
{
d[i][j] = g[i][j] = s[j] - '0';
if(d[i][j] == 0) d[i][j] = INF;
if(i == j) d[i][j] = 0;
}
}
cin >> m;
for(int i=1; i<=m; i++) cin >> p[i];
for(int k=1; k<=n; k++)
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++) down(d[i][j], d[i][k] + d[k][j]);
vec.push_back(p[1]);
int lst = p[1], cur = 0;
for(int i=2; i<=m; i++)
{
cur += d[p[i-1]][p[i]];
if(d[lst][p[i]] < cur)
{ lst = p[i-1]; vec.push_back(lst); cur = d[lst][p[i]]; }
}
vec.push_back(p[m]); cout << vec.size() << '\n';
for(int i=0; i<vec.size(); i++) cout << vec[i] << " \n"[i==vec.size()-1];
return 0;
}
参考文献: