题目链接
http://codeforces.com/contest/721/problem/C
思路
二分最多能够经过多少个点,然后dp判断
状态表示:
d[i][j]
:当前在第i个点,经过了j个点的最小距离
转移方程:
d[i][j]=min(d[k][j−1]+w(i,k),d[i][j])
(k是i的前驱,w(k, i)表示k到i的边长)
边界条件:
当i == 1时,只要
j≤1
即可,即走到起点的时候,实际经过的点的数目可以不到j
细节
- 二分的时候L = 1,如果L = 2的话不会进入dp,因此不会记录路径
- 记录路径的时候也需要开2维
- 建图的时候边要反向,因为找的是前驱
代码
#include <iostream>
#include <cstring>
#include <stack>
#include <vector>
#include <set>
#include <map>
#include <cmath>
#include <queue>
#include <sstream>
#include <iomanip>
#include <fstream>
#include <cstdio>
#include <cstdlib>
#include <climits>
#include <deque>
#include <bitset>
#include <algorithm>
using namespace std;
#define PI acos(-1.0)
#define LL long long
#define PII pair<int, int>
#define PLL pair<LL, LL>
#define mp make_pair
#define IN freopen("in.txt", "r", stdin)
#define OUT freopen("out.txt", "wb", stdout)
#define scan(x) scanf("%d", &x)
#define scan2(x, y) scanf("%d%d", &x, &y)
#define scan3(x, y, z) scanf("%d%d%d", &x, &y, &z)
#define sqr(x) (x) * (x)
const int maxn = 5000 + 5;
const int INF = 0x3e3e3e3e;
struct Edge {
int from, to, dist;
Edge(int u, int v, int w) : from(u), to(v), dist(w) {
}
};
vector<Edge> edges;
vector<int> G[maxn];
int n, m, T;
void addedge(int u, int v, int w) {
edges.push_back(Edge(u, v, w));
G[u].push_back(edges.size() - 1);
}
int d[maxn][maxn], pa[maxn][maxn];
int dp(int i, int j) {
if (d[i][j] != -1) return d[i][j];
if (i == 1) return d[i][j] = j <= 1 ? 0 : INF;
d[i][j] = INF;
for (int ii = 0; ii < G[i].size(); ii++) {
Edge e = edges[G[i][ii]];
int k = e.to;
int t = dp(k, j - 1) + e.dist;
if (t < d[i][j]) {
d[i][j] = t;
pa[i][j] = k;
}
}
return d[i][j];
}
bool judge(int x) {
memset(d, -1, sizeof(d));
int t = dp(n, x);
return t <= T;
}
void print(int u, int x) {
if (u == 1) return;
print(pa[u][x], x - 1);
printf(" %d", u);
}
int main() {
scan3(n, m, T);
for (int i = 0; i < m; i++) {
int x, y, z;
scan3(x, y, z);
addedge(y, x, z);
}
int L = 1, R = n, M = (L + R) >> 1;
while (L < R) {
if (R == L + 1) {
if (judge(R)) M = R;
else {
judge(L);
M = L;
}
break;
} else {
M = (L + R) >> 1;
if (judge(M)) L = M;
else R = M;
}
}
printf("%d\n", M);
printf("1");
print(n, M);
return 0;
}