区间覆盖题解-EOJ2799
来源:
题意
给定 \(n\) 个点,\(m\) 个操作,每次操作可以将第 \(L_i\) 个点到第 \(R_i\) 个点覆盖,耗费是 \(W_i\)。
问至少覆盖(可以重复覆盖) \(k\) 个点的最小耗费是多少?
题解
-
定义:
Cost[l][r]为覆盖区间\([l,r]\)的最小代价,cost[l][r]为覆盖区间\([l,r]\)的代价 -
考虑dp状态定义:设
dp[i][j]为覆盖前i个点中的j个点所需的最小代价。 -
考虑转移
-
考虑一个操作\(L,R,W\),覆盖区间长度为\(len = R-L+1\)。考虑操作之前状态为,前\(L-1\)个点的状态\(dp[L-1,x]\) ,操作后则多覆盖\(len\)个点,花费代价\(Cost[L,R]\) 转移到状态\(dp[R,x+len]\)。
\[dp[R,x] = \min(dp[R,x],dp[L-1][x-len]+Cost[L,R])
\]
- 考虑\(Cost[L,R]\)的计算,即覆盖区间\([L,R]\)所需的最小代价。
- 由于区间可重复覆盖,前\(R\) 个数中覆盖区间\([L,R]\)所需的最小代价为包含该区间的操作区间代价的最小值。
\[Cost[L][R] = \min_{L\le l\le R}cost[l][R]
\]
- 故状态转移方程为
\[dp[i][j] = \min(dp[i][j],\quad\min_{L\le l\le i} dp[L-1][j]+cost[l][i])
\]
- 最终答案为
\[ans = \min_{k\le i\le n} dp[n][i]
\]
AC代码
#include <bits/stdc++.h>
#define ll long long
//#define int long long
#define IOS ios::sync_with_stdio(false);cin.tie(nullptr);
#define endl '\n'
const int inf = 0x3f3f3f3f;
const ll infll = 0x3f3f3f3f3f3f3f3f;
const double PI = acos(-1.0);
using namespace std;
//ifstream fin("input.txt");
//ofstream fout("output.txt");
//#define cin fin
//#define cout fout
int n,m,k;
const int N = 305,M=1e5+10;
ll dp[N][N];
ll cost[N][N];
signed main()
{
IOS
int t;cin>>t;
for(int cs=0;cs<t;cs++) {
cin>>n>>m>>k;
for(int i=0;i<=n+5;i++) {
for(int j=0;j<=n+5;j++) {
dp[i][j]=infll;
cost[i][j]=infll;
}
}
dp[0][0]=0;
for(int i=1;i<=m;i++) {
int l,r,w;cin>>l>>r>>w;
cost[l][r] = min(cost[l][r],w*1ll);
}
for (int len=n; len>=1; len--) {
for (int l=1; l+len-1<=n;l++) {
int r = l+len-1;
if (l-1>=1) cost[l][r] = min(cost[l][r],cost[l-1][r]);
}
}
for(int i=1;i<=n;i++) {
for(int j=0;j<=n;j++) {
dp[i][j] = dp[i-1][j];
}
for(int l=1;l<=i;l++) {
if(cost[l][i]==infll) continue;
int len = i-l+1;
for(int j=len;j<=n;j++) {
if(l-1>=0)
dp[i][j] = min(dp[i][j],dp[l-1][j-len]+cost[l][i]);
}
}
}
cout<<"case #"<<cs<<":\n";
ll ans = infll;
for(int i=k;i<=n;i++) ans = min(ans,dp[n][i]);
if(ans==infll) cout<<-1<<endl;
else cout<<ans<<endl;
}
//fin.close(),fout.close();
return 0;
}

浙公网安备 33010602011771号