树形DP 【codeforces 793D】Presents in Bankopolis

来源:互联网 发布:罗宇回忆录 知乎 编辑:程序博客网 时间:2024/06/05 19:37

传送门


判断是否是一道树规题:

即判断数据结构是否是一棵树,然后是否符合动态规划的要求。如果是,那么执行以下步骤,如果不是,那么换台。

建树:通过数据量和题目要求,选择合适的树的存储方式。

如果节点数小于5000,那么我们可以用邻接矩阵存储,如果更大可以用邻接表来存储(注意边要开到2*n,因为是双向的。这是血与泪的教训)。如果是二叉树或者是需要多叉转二叉,那么我们可以用两个一维数组brother[],child[]来存储(这一点下面会仔细数的)。

写出树规方程:通过观察孩子和父亲之间的关系建立方程。我们通常认为,树形DP的写法有两种:
a.根到叶子: 不过这种动态规划在实际的问题中运用的不多。本文只有最后一题提到。
b.叶子到根: 既根的子节点传递有用的信息给根,完后根得出最优解的过程。这类的习题比较的多。



D. Presents in Bankopolis
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Bankopolis is an incredible city in which all the n crossroads are located on a straight line and numbered from 1 to n along it. On each crossroad there is a bank office.

The crossroads are connected with m oriented bicycle lanes (the i-th lane goes from crossroad ui to crossroad vi), the difficulty of each of the lanes is known.

Oleg the bank client wants to gift happiness and joy to the bank employees. He wants to visit exactly k offices, in each of them he wants to gift presents to the employees.

The problem is that Oleg don't want to see the reaction on his gifts, so he can't use a bicycle lane which passes near the office in which he has already presented his gifts (formally, the i-th lane passes near the office on the x-th crossroad if and only if min(ui, vi) < x < max(ui, vi))). Of course, in each of the offices Oleg can present gifts exactly once. Oleg is going to use exactly k - 1bicycle lane to move between offices. Oleg can start his path from any office and finish it in any office.

Oleg wants to choose such a path among possible ones that the total difficulty of the lanes he will use is minimum possible. Find this minimum possible total difficulty.

Input

The first line contains two integers n and k (1 ≤ n, k ≤ 80) — the number of crossroads (and offices) and the number of offices Oleg wants to visit.

The second line contains single integer m (0 ≤ m ≤ 2000) — the number of bicycle lanes in Bankopolis.

The next m lines contain information about the lanes.

The i-th of these lines contains three integers uivi and ci (1 ≤ ui, vi ≤ n1 ≤ ci ≤ 1000), denoting the crossroads connected by the i-th road and its difficulty.

Output

In the only line print the minimum possible total difficulty of the lanes in a valid path, or -1 if there are no valid paths.

Examples
input
7 441 6 26 2 22 4 22 7 1
output
6
input
4 342 1 21 3 23 4 24 1 1
output
3
Note

In the first example Oleg visiting banks by path 1 → 6 → 2 → 4.

Path 1 → 6 → 2 → 7 with smaller difficulity is incorrect because crossroad 2 → 7 passes near already visited office on the crossroad 6.

In the second example Oleg can visit banks by path 4 → 1 → 3.


【题意】 

给你n个点, 
这n个点 
从左到右1..n依序排; 
然后给你m条有向边; 
然后让你从中选出k个点. 
这k个点形成的一条路径; 
且在路径中,一个被访问过的点不会经过两次或以上; 
比如从1->3(1和3被访问过) 
然后再从3->4(1,3,4都被访问过) 
再从4->2(这时会又经过3号节点,而3号节点之前被访问过,所以不合法) 
这就不是合法的; 


首先我们设置一个 dp[st][ed][k] 表示从 st 点出发能到达的某个方向最远处 ed 点且剩余 k 个点未走,既然说到某一个方向,那么这里肯定是正向和反向,针对于正向和反向的不同还要有分别的状态转移方程,存图设置一个 mp[u][v],记住这里是有向图,搞成无向图会在第四组数据 WA,

设置完上边两个数组,剩下的也就是一个递归搜索,打个比方说,也就是如果从 st 在某一个方向最远可以到达 ed,那么这个区间中的任意一个都可以到达,假如此时到达了 mid,那么下一次分别是可以从 mid 到 st 和 mid 到 ed。

等于左右都走一边

#include <iostream>#include <cstring>#include <algorithm>#include <stdio.h>#define POSTIVE 1#define REBERSE 0using namespace std;const int MAXN = 88;const int INF = 0x3f3f3f3f;int dp[MAXN][MAXN][MAXN];int mp[MAXN][MAXN];int n, k, m;int u, v, c;void init(){    memset(dp, -1, sizeof(dp));    memset(mp, 0x3f, sizeof(mp));}int getDP(int st, int ed, int k, int dir){    if (dp[st][ed][k] != -1)    {        return dp[st][ed][k];    }    if (k == 0)    {        dp[st][ed][k] = 0;        return dp[st][ed][k];    }    int res = INF;    if (dir)    {        for (int i = st + 1; i < ed; i++)        {            if (mp[st][i] != INF)            {                res = min(res, mp[st][i] + getDP(i, st, k - 1, REBERSE));                res = min(res, mp[st][i] + getDP(i, ed, k - 1, POSTIVE));            }        }    }    else    {        for (int i = ed + 1; i < st; i++)        {            if (mp[st][i] != INF)            {                res = min(res, mp[st][i] + getDP(i, st, k - 1, POSTIVE));                res = min(res, mp[st][i] + getDP(i, ed, k - 1, REBERSE));            }        }    }    dp[st][ed][k] = res;    return dp[st][ed][k];}int main(int argc, const char * argv[]){//    freopen("/Users/zyj/Desktop/input.txt", "r", stdin);    init();    scanf("%d%d%d", &n, &k, &m);    for (int i = 1; i <= m; i++)    {        scanf("%d%d%d", &u, &v, &c);        mp[u][v] = min(mp[u][v], c);  //  可能会有重边,重边只保留最短边    }    int res = INF;    for (int i = 1; i <= n; i++)        //  以任何一个点为起点    {        res = min(res, getDP(i, 0, k - 1, REBERSE));        res = min(res, getDP(i, n + 1, k - 1, POSTIVE));    }    if (res == INF)    {        cout << "-1\n";    }    else    {        cout << res << '\n';    }    return 0;}


阅读全文
0 0