CodeForces - 793D 區間dp,記憶化
阿新 • • 發佈:2017-10-04
記憶化 ini %d 單向 ble targe set skip ref
CodeForces - 793D
題意:一條筆直街道上有標號為 1~n 的 n 個點,有 m 條帶邊權的單向邊。要找一條經過 k 個點的路徑和,限制:每次走過的邊不能跨過已走過的點。 比如點 3 已經走過,則後面的邊不能是 min(u,v) < 3 < max(u,v) 。
tags: 80 個點,一開始上暴搜 T 了,看了題解才知道是區間 dp。。
dp[cur][l][r][skip] 為當前走了skip步在 cur點,下一步可到達區間 [l,r] 狀態,走完 k 步最少還要多少距離。
然後就是記憶化遞歸。
如果有邊 cur -> to,且 to 在[l,r]之中,則 dp[cur][l][r][skip] = min(dp[cur][l][r][skip], dp[to][st][ed][skip+1] +邊權 ) ; st, ed為走到 to後新的區間。
#include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define rep(i,a,b) for (int i=a; i<=b; ++i) #define per(i,b,a) for (int i=b; i>=a; --i) #define mes(a,b) memset(a,b,sizeof(a)) #define INF 0x3f3f3f3f #define MP make_pair #define PB push_back #definefi first #define se second typedef long long ll; const int N = 85; int n, k, m, G[N][N]; int dp[N][N][N][N]; void Init() { mes(G, INF); mes(dp, -1); } int solve(int cur, int l, int r, int skip) { if(dp[cur][l][r][skip]!=-1) return dp[cur][l][r][skip]; // 這裏dp不要定義為INF,因為下面不可能的情況會返回INF,這樣不可能的情況就相當於沒有記憶化if(skip==k) return dp[cur][l][r][skip] = 0; int res = INF; rep(i,l,r) if(G[cur][i]!=INF) { int st=l, ed=r; if(i<cur) ed=cur-1; else st=cur+1; res = min(res, solve(i, st, ed, skip+1)+G[cur][i] ); } return dp[cur][l][r][skip] = res; } int main() { scanf("%d%d%d", &n, &k, &m); Init(); int u, v, w; rep(i,1,m) { scanf("%d%d%d", &u, &v, &w); G[u][v] = min(G[u][v], w); } int ans=INF; rep(i,1,n) ans = min(ans, solve(i, 1, n, 1) ); if(ans==INF) ans=-1; printf("%d\n", ans); return 0; }
CodeForces - 793D 區間dp,記憶化