嘘~ 正在从服务器偷取页面 . . .

CF1204C Anna, Svyatoslav and Maps 题解


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;
}

参考文献

[1] https://te5555.blog.luogu.org/solution-cf1204c


文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录