拓扑序+dp Codeforces Round #374 (Div. 2) C

http://codeforces.com/contest/721/problem/C

题目大意:给你有向路,每条路都有一个权值t,你从1走到n,最多花费不能超过T,问在T时间内最多能访问多少城市?

思路:dp确实好玩,然而我不会TAT

首先我们定义dp[i][j]表示从i走到n,途中经过j个城市所需要的花费。接下来就枚举拓扑序就好了

//看看会不会爆int!数组会不会少了一维!
//取物问题一定要小心先手胜利的条件
#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define ALL(a) a.begin(), a.end()
#define pb push_back
#define mk make_pair
#define fi first
#define se second
#define haha printf("haha
")
const int maxn = 5000 + 5;
vector<pair<int, int> > G[maxn];
int n, m, T;
bool vis[maxn];
int par[maxn][maxn], dp[maxn][maxn];
///定义从i走到n,经过j个地方所需要的最小时间花费

void dfs(int u){
    vis[u] = true;
    int len = G[u].size();
    for (int i = 0; i < len; i++){
        pair<int, int> p = G[u][i];
        int v = p.fi, val = p.se;
        if (!vis[v]) dfs(v);
        for (int j = 2; j <= n; j++){
            if (dp[u][j] > dp[v][j - 1] + val){
                dp[u][j] = dp[v][j - 1] + val;
                par[u][j] = v;
            }
        }
    }
}

int main(){
    cin >> n >> m >> T;
    memset(dp, 0x3f, sizeof(dp));
    dp[n][1] = 0;
    for (int i = 1; i <= m; i++){
        int u, v, val;
        scanf("%d%d%d", &u, &v, &val);
        G[u].pb(mk(v, val));
    }
    memset(par, -1, sizeof(par));
    dfs(1);
/*
    for (int i = 1; i <= n; i++){
        for (int j = 1; j <= n; j++){
            ///printf("%d ", dp[i][j]);
            printf("%d ", par[i][j]);
        }
        printf("
");
    }
*/
    for (int i = n; i >= 1; i--){
        if (dp[1][i] <= T){
            printf("%d
", i);
            for (int j = 1; j != -1; j = par[j][i], i--){
                printf("%d ", j);
            }
            break;
        }
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/heimao5027/p/5927919.html