Codeforces Round #186 (Div. 2) D. Ilya and Roads(区间类动态规划)

题目大意

一条直线上有 n(1≤n≤300) 个点可以用来修洞,有 m(1≤m≤105) 个建筑公司,每个建筑公司 i(1≤i≤m) 需要 ci(1≤ci≤109) 的价钱修理包含于区间 [Li, Ri](1≤Li≤Ri≤n) 中的一段连续的洞。问至少修建 k(1≤k≤n) 个洞需要花费的最小价钱

做法分析

初一看像是求最大流,但是仔细一想,如果是网络流的话,建好的网络太大,绝对TLE,而且貌似这还不好建图

果断放弃,想想DP怎么做

可以这样想:f[i][p] 表示前 i 个洞中修建了 p 个洞需要花费的最小价钱,转移方程为:

         f[i][p] = min{ f[j][p-i-j]+c[j][i] },1≤j≤i-1

         其中 c[i][j] 表示 [i+1, j] 这段连续的区间中的洞用一个公司修需要花费的最小代价。

这个DP是 n3 的,不会T,现在就想想 c[i][j] 怎么求

刚开始的时候,我们得到每个公司修建的最大区间,先初始化这些区间

然后可以这样转移: 

这样就求出所有的区间 [i, j] 用一个公司修建需要花费的最小代价了

参考代码

 1 #include <iostream>
 2 #include <cstring>
 3 #include <cstdio>
 4 
 5 using namespace std;
 6 
 7 typedef long long LL;
 8 const int N=306;
 9 const LL INF=(1LL)<<60;
10 
11 LL c[N][N], f[N][N], ans;
12 int n, m, Min;
13 
14 int main()
15 {
16     scanf("%d%d%d", &n, &m, &Min);
17     for(int i=0; i<=n; i++)
18         for(int j=0; j<=n; j++) c[i][j]=f[i][j]=INF;
19     for(int i=0, a, b; i<m; i++)
20     {
21         LL d;
22         scanf("%d%d%I64d", &a, &b, &d);
23         if(a>b) swap(a, b);
24         c[a-1][b]=min(c[a-1][b], d);
25     }
26     for(int i=0; i<=n; i++)
27         for(int j=n; j>=i; j--)
28         {
29             c[i+1][j]=min(c[i+1][j], c[i][j]);
30             c[i][j-1]=min(c[i][j-1], c[i][j]);
31         }
32     f[0][0]=0LL;
33     for(int i=1; i<=n; i++)
34         for(int j=0; j<=i; j++)
35         {
36             f[i][j]=f[i-1][j];
37             for(int k=0; k<i; k++)
38                 f[i][j]=min(f[i][j], f[k][j-i+k]+c[k][i]);
39         }
40     ans=INF;
41     for(int i=Min; i<=n; i++) ans=min(ans, f[n][i]);
42     if(ans==INF) ans=-1LL;
43     printf("%I64d\n", ans);
44     return 0;
45 }
D. Ilya and Roads

题目链接 & AC通道

Codeforces Round #186 (Div. 2) D. Ilya and Roads

原文地址:https://www.cnblogs.com/zhj5chengfeng/p/3118734.html