Codeforces 793D Presents in Bankopolis【Dp+记忆化搜索】

351 篇文章 2 订阅

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 - 1 bicycle 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 ui, vi and ci (1 ≤ ui, vi ≤ n, 1 ≤ 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 4
4
1 6 2
6 2 2
2 4 2
2 7 1
Output
6
Input
4 3
4
2 1 2
1 3 2
3 4 2
4 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个点,要求然你找到一条长度为K的链,起点终点不限,使得其路径总和最小。

要求一个点不能走多次。

另外假设点i已经走过了,那么我们不能从比i编号大的点走到比i编号小的点,同理也不能从比i编号小的点走到比i编号大的点。


思路(思路源自:http://blog.csdn.net/jeremy1149/article/details/70579664):


吐槽:

有时候Dp去写记忆化真的很好理解也很好实现,写了好半天for的写的心累。。。。。。。。。。。。


1、问题的模型肯定是建立在最短路上来的,对于限制型最短路问题,我们可以升其维度来改变dp的方式。

那么设定dp【i】【l】【r】【cur】表示当前剩下i步需要走,此时在cur这个点,下一步需要在区间(l,r)内找到一个点进行行进的点的最短路径。

那么就有:

dp【i】【l】【r】【cur】=min(dp【i】【nexL】【nexR】【v】,dp【i】【l】【r】【cur】);这里l<v<r,,然后讨论v和cur之间的大小关系能够确定nexL,和nexR.


2、然后我们枚举终点然后进行记忆化即可,过程维护一个最小值。


Ac代码:

#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
int n,m,k;
int a[85][85];
int dp[85][85][85][85];
int Dp(int k,int l,int r,int cur)
{
    if(dp[k][l][r][cur]==-1)
    {
        if(k==1)
        {
            dp[k][l][r][cur]=0;
            return dp[k][l][r][cur];
        }
        else
        {
            dp[k][l][r][cur]=0x3f3f3f3f;
            for(int i=1;i<=n;i++)
            {
                if(i==cur)continue;
                if(i>l&&i<r&&a[cur][i]<0x3f3f3f3f)
                {
                    int L=l,R=r;
                    if(i>cur)L=cur;
                    else R=cur;
                    dp[k][l][r][cur]=min(dp[k][l][r][cur],Dp(k-1,L,R,i)+a[cur][i]);
                }
            }
            return dp[k][l][r][cur];
        }
    }
    else return dp[k][l][r][cur];
}
int main()
{
    while(~scanf("%d%d",&n,&k))
    {
        scanf("%d",&m);
        for(int i=0;i<=82;i++)
        {
            for(int j=0;j<=82;j++)
            {
                a[i][j]=0x3f3f3f3f;
            }
        }
        for(int i=0;i<m;i++)
        {
            int x,y,w;
            scanf("%d%d%d",&x,&y,&w);
            a[x][y]=min(w,a[x][y]);
        }
        memset(dp,-1,sizeof(dp));
        int output=0x3f3f3f3f;
        for(int i=1;i<=n;i++)
        {
            output=min(output,Dp(k,0,n+1,i));
        }
        if(output==0x3f3f3f3f||output==-1)printf("-1\n");
        else
        printf("%d\n",output);
    }
}












评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值