no crossing(代码源每日一题)
作者:互联网
no crossing(代码源每日一题)
no crossing - 题目 - Daimayuan Online Judge
区间DP
- 从暴力思路入手,站在 now 号点,当前可行的区间是 [l, r], 还要走 k 步,因此状态数为 \(n^4\), 总转移复杂度为 \(m\), 总复杂度为 \(n^4+m\)
- 因为路径的性质,不能横跨已经走过的点,因此 now 号点一定是下一个区间的左/右端点,因此可简化掉 now 这个状态, 总复杂度为 \(n^3+m\)
记 \(f[l][r][k][0/1]\) 表示当前能走的区间为 (l, r), 还有 k 步,当前站在左端点(0)还是右端点(1)
起始状态为枚举一开始站在 i 号点,i 为左端点还是右端点,即 \(dfs(0,i,k-1,1)\) 与 \(dfs(i,n+1,k-1,0)\)
注意此处边界为 0 和 n + 1,因为边界总是之前的点走过的或者 1,n,为了方便,设 dfs 的过程中令边界都不能取,所以一开始的边界为 0,n + 1,就保证了 1,n 是可取的
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
using namespace std;
#define endl "\n"
typedef long long ll;
typedef pair<int, int> PII;
const int INF = 0x3f3f3f3f;
const int N = 110;
int f[N][N][N][2];//f[l][r][k][0/1]为当前可行的区间是[l,r],还要走k步,当前在l/r点
struct Edge
{
int to, val;
};
vector<vector<Edge> > G(N);
int n, k, m;
void add(int u, int v, int w)
{
G[u].push_back({v, w});
}
int dfs(int l, int r, int k, int d)
{
if (k <= 0)
return 0;
int &now = f[l][r][k][d];
if (~now)
return now;
int u = (d ? r : l);
int res = INF;
for (auto [v, w] : G[u])
{
if (v <= l || v >= r)
continue;
res = min(res, w + dfs(v, r, k - 1, 0));
res = min(res, w + dfs(l, v, k - 1, 1));
}
return now = res;
}
int main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> n >> k >> m;
while(m--)
{
int u, v, w;
cin >> u >> v >> w;
add(u, v, w);
}
int ans = INF;
memset(f, -1, sizeof f);
for (int i = 1; i <= n; i++)
{
ans = min(ans, dfs(i, n + 1, k - 1, 0));
ans = min(ans, dfs(0, i, k - 1, 1));
}
cout << (ans == INF ? -1 : ans) << endl;
return 0;
}
标签:now,no,int,res,代码,dfs,端点,crossing,include 来源: https://www.cnblogs.com/hzy717zsy/p/16368390.html