代码源 Div1#104no crossing,Codeforces 793D,2100分,区间dp

Posted 小哈里

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了代码源 Div1#104no crossing,Codeforces 793D,2100分,区间dp相关的知识,希望对你有一定的参考价值。

problem


D. Presents in Bankopolis

time limit per test2 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard 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
inputCopy
7 4
4
1 6 2
6 2 2
2 4 2
2 7 1
outputCopy
6
inputCopy
4 3
4
2 1 2
1 3 2
3 4 2
4 1 1
outputCopy
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号节点之前被访问过,所以不合法),这就不是合法的。

solution

  • 每次走完之后都有一个接下来能走的区间,比如当前走的区间为[a,b],然后你从b走到了a,b中的某个位置u(显然是往左走了),则对应了两个状态[a,u]和[u,b],这里[a,u]只能是往左走的,而[u,b]只能是往右走的(不然就经过第二次,不合法了,再之后的移动中也只能单项移动
  • ->区间DP,设f[i][j][k][0…1]表示走了i条边,然后当前能够走的区间为j,k。
    然后0表示当前起点在i然后向右走,1表示当前起点在j然后向左走。
  • f[i][j][k][0]=min(f[i−1][j][u][1],f[i−1][u][k][0])+cost[j][u];
    f[i][j][k][1]=min(f[i−1][j][u][1],f[i−1][u][k][0])+cost[j][u];
    imax=k-1
    然后对于k=1的情况直接输出0;
    否则在做DP的过程中一边更新答案就好了
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 110, inf = 1e9+10;

vector<pair<int,int> >G[maxn];
int f[maxn][maxn][maxn][2];

int main()
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int n, k;  cin>>n>>k;
    int m;  cin>>m;
    for(int i = 1; i <= m; i++)
        int x, y, z;  cin>>x>>y>>z;
        G[x].push_back(make_pair(y,z));
    
    if(k==1)return cout<<0<<"\\n", 0;
    int ans = inf;
    for(int i = 1; i <= k-1; i++)
        for(int l = n; l >= 0; l--)
            for(int r = l+1; r<= n+1; r++)
                f[i][l][r][0] = inf;
                for(auto tmp : G[l])//从l出发所有能到[l,r]中的点
                    int y = tmp.first, cost = tmp.second;
                    if(l<y && y<r)
                        f[i][l][r][0] = min(f[i][l][r][0], f[i-1][y][r][0]+cost);
                        f[i][l][r][0] = min(f[i][l][r][0], f[i-1][l][y][1]+cost);
                    
                
                f[i][l][r][1] = inf;
                for(auto tmp : G[r])//从l出发所有能到[l,r]中的点
                    int y = tmp.first, cost = tmp.second;
                    if(l<y &&y<r)
                        f[i][l][r][1] = min(f[i][l][r][1], f[i-1][y][r][0]+cost);
                        f[i][l][r][1] = min(f[i][l][r][1], f[i-1][l][y][1]+cost);
                    
                
                if(i==k-1)
                    ans = min(ans, f[i][l][r][1]);
                    ans = min(ans, f[i][l][r][0]);
                
            
        
    
    if(ans >= inf)cout<<-1<<"\\n";
    else cout<<ans<<"\\n";
    return 0;




以上是关于代码源 Div1#104no crossing,Codeforces 793D,2100分,区间dp的主要内容,如果未能解决你的问题,请参考以下文章

代码源 Div1 - 105#451. Dis(倍增求LCA)

代码源 Div1 - 101#61. 二分答案(贪心)

代码源 Div1 - 107#452. 序列操作(思维)CF1198B

代码源 Div1 - 102#323. 最长因子链(dp)

代码源 Div1 - 105#451. Dis(倍增求LCA)

代码源 Div1 - 107#452. 序列操作(思维)CF1198B