cf793 D. Presents in Bankopolis(区间dp)
题意:
给定一个有向图,求恰经过k个点的最短路径的长度。
每个点最多走一次。且走一条新边 x->y 时,不能有一个之前走过的点的编号 u 在 x,y 之间(即 \(min(x,y)<u<max(x,y)\))
\(1\le n,k \le 100, 0\le m \le 2000\)
思路:
这题跟图没什么关系。把图看成一条 \([1,n]\) 整点线段,画图模拟一下走的过程。
考虑反向过程,把所有边都反向。\(f(k,l,r,0/1)\) 表示 \(l\to r\) 作为第 \(k-1\) 条边(走了 \(k\) 个点),方向是x轴负向/正向,的最短路长度
用题目给的边初始化 \(f(2,\cdots)\),即走了一条边,两个点
注意特判,k=1时只能到一个点,输出1。
const int N = 105;
int n, m, K, w[N][N], f[N][N][N][2], ans = INF;
signed main()
{
memset(w, INF, sizeof w);
memset(f, INF, sizeof f);
cin >> n >> K >> m;
while(m--)
{
int a, b, c; cin >> b >> a >> c; //反向
w[a][b] = min(w[a][b], c); //边权,小心重边
if(a < b) f[2][a][b][1] = w[a][b];
else f[2][b][a][0] = w[a][b];
}
if(K == 1) return cout << 0, 0;
for(int k = 3; k <= K; k++)
for(int l = 1; l <= n - 1; l++)
for(int r = l + 1; r <= n; r++)
for(int x = l + 1; x < r; x++)
f[k][l][r][1] = min({f[k][l][r][1],
f[k-1][l][x][0] + w[l][r], f[k-1][l][x][1] + w[x][r]}),
f[k][l][r][0] = min({f[k][l][r][0],
f[k-1][x][r][0] + w[x][l], f[k-1][x][r][1] + w[r][l]});
for(int l = 1; l <= n - 1; l++)
for(int r = l + 1; r <= n; r++)
ans = min({ans, f[K][l][r][0], f[K][l][r][1]});
if(ans == INF) ans = -1;
cout << ans;
}

浙公网安备 33010602011771号