CF721C Journey problem solution

Posted by prashanth on Wed, 12 Jan 2022 03:57:20 +0100

First of all, it can be found that this problem is actually similar to a knapsack problem on DAG.

Then we have an obvious approach:

set up f [ v ] [ t ] f[v][t] f[v][t] indicates from point 1 1 1 arrival point v v v. Path length is t t The maximum number of points in all schemes of t, the transfer equation is trivial, which is omitted here.

however T ≤ 1 0 9 T \leq 10^9 If T ≤ 109, the space will explode.

Fortunately, the answer must be less than or equal to n n n, at the same time n ≤ 5000 n \leq 5000 n ≤ 5000, which inspires us to consider O ( n 2 ) O(n^2) O(n2) space algorithm.

Let's think from another angle: since enumerating the maximum distance of points is not feasible, is it feasible to enumerate the points to find the minimum distance?

Observe the data range, which is obviously feasible in terms of complexity.

So we try to consider the transfer equation:

set up f [ v ] [ t ] f[v][t] f[v][t] indicates from point 1 1 1 arrival point v v v. The number of points passed is t t The shortest path in all schemes of t.

So we have the transfer equation: (where p r e f i x ( v ) prefix(v) prefix(v) indicates a point v v The precursor of v, that is, all reachable points v v The point of v, w w w means edge u → v u\to v Length of u → v)

f [ v ] [ t ] = min ⁡ u ∈ p r e f i x ( v ) ( f [ u ] [ t − 1 ] + w ) [ f [ u ] [ t − 1 ] + w < = T ] f[v][t] = \min_{u \in prefix(v)} (f[u][t - 1] + w)[f[u][t - 1] + w <= T] f[v][t]=u∈prefix(v)min​(f[u][t−1]+w)[f[u][t−1]+w<=T]

Why the shortest path? Because we don't care about the length of the path, only whether it doesn't exceed T T T. From the perspective of greed, it is obviously optimal to choose the shortest path here.

While transferring, we record one g [ v ] [ t ] g[v][t] g[v][t], denotes f [ v ] [ t ] f[v][t] f[v][t] by which u u u transferred to facilitate the final output of the answer.

Code: (don't rush to copy)

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cassert>
#include<cstring>
#include<vector>
#include<queue>

#define MAXN 5005

using namespace std;

int n, m, k, in[MAXN], f[MAXN][MAXN], g[MAXN][MAXN];
vector<pair<int, int> > vec[MAXN];

inline void Toposort()
{
    queue<int> q;
    q.push(1), f[1][1] = 0, g[1][1] = 1;
    while(!q.empty())
    {
        int u = q.front(); q.pop();
        for(register vector<pair<int, int> > :: iterator it = vec[u].begin(); it != vec[u].end(); it++)
        {
            int v = it -> first, w = it -> second;
            for(register int i = 1; i <= n; i++)
            {
                if(g[u][i - 1] && f[u][i - 1] + w <= k && f[u][i - 1] + w < f[v][i])
                {
                    f[v][i] = f[u][i - 1] + w;
                    g[v][i] = u;
                }
            }
            --in[v]; if(!in[v]) q.push(v);
        }
    }
    return;
}

inline void Output(int u, int k)
{
    if(u > 1) Output(g[u][k], k - 1);
    printf("%d ", u);
    return;
}

int main()
{
    #ifdef FILE
        freopen("Input.in", "r", stdin);
        freopen("Output.out", "w", stdout);
    #endif
    scanf("%d%d%d", &n, &m, &k);
    for(register int i = 1; i <= m; i++)
    {
        int u, v, w; scanf("%d%d%d", &u, &v, &w);
        vec[u].push_back(make_pair(v, w));
        ++in[v];
    }
    memset(f, 0x3F, sizeof f);
    Toposort();
    int t;
    for(t = n; t > 1; t--) if(g[n][t]) break;
    printf("%d\n", t);
    Output(n, t);
    return 0;
}

But the above code can't pass. Hack data:

4 4 10
2 1 1
2 3 1
1 3 1
3 4 1

What are the characteristics of this set of data? The source point of the DAG is not a point 1 1 1 !

Although point 1 1 All direct and indirect precursors of 1 will not affect the answer, but they will affect the topological sorting process.

Like the upper edge 2 → 3 2 \to 3 2 → 3, although point 2 2 2 is not accessed in topology sorting, but this edge is point-to-point 3 3 The penetration of 3 still exists 1 1 1.

So we need to do DFS first and point it out 1 1 All direct and indirect precursors of 1 have no influence on the penetration of the midpoint of the topology map.

code:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cassert>
#include<cstring>
#include<vector>
#include<queue>

#define MAXN 5005

using namespace std;

int n, m, k, in[MAXN], f[MAXN][MAXN], g[MAXN][MAXN];
bool vis[MAXN];
vector<pair<int, int> > vec[MAXN];

inline void DFS(int u)
{
    vis[u] = true;
    for(register vector<pair<int, int> > :: iterator it = vec[u].begin(); it != vec[u].end(); it++) if(!vis[it -> first]) DFS(it -> first);
    return;
}

inline void Toposort()
{
    queue<int> q;
    q.push(1), f[1][1] = 0, g[1][1] = 1;
    while(!q.empty())
    {
        int u = q.front(); q.pop();
        for(register vector<pair<int, int> > :: iterator it = vec[u].begin(); it != vec[u].end(); it++)
        {
            int v = it -> first, w = it -> second;
            for(register int i = 1; i <= n; i++)
            {
                if(g[u][i - 1] && f[u][i - 1] + w <= k && f[u][i - 1] + w < f[v][i])
                {
                    f[v][i] = f[u][i - 1] + w;
                    g[v][i] = u;
                }
            }
            --in[v]; if(!in[v]) q.push(v);
        }
    }
    return;
}

inline void Output(int u, int k)
{
    if(u > 1) Output(g[u][k], k - 1);
    printf("%d ", u);
    return;
}

int main()
{
    #ifdef FILE
        freopen("Input.in", "r", stdin);
        freopen("Output.out", "w", stdout);
    #endif
    scanf("%d%d%d", &n, &m, &k);
    for(register int i = 1; i <= m; i++)
    {
        int u, v, w; scanf("%d%d%d", &u, &v, &w);
        vec[u].push_back(make_pair(v, w));
        ++in[v];
    }
    memset(f, 0x3F, sizeof f);
    DFS(1);
    for(register int i = 1; i <= n; i++) if(!vis[i]) for(register vector<pair<int, int> > :: iterator it = vec[i].begin(); it != vec[i].end(); it++) --in[it -> first];
    Toposort();
    int t;
    for(t = n; t > 1; t--) if(g[n][t]) break;
    printf("%d\n", t);
    Output(n, t);
    return 0;
}

E N D \mathit{END} END

Topics: Dynamic Programming Graph Theory