牛客网暑期ACM多校训练营(第四场): B. Interval Revisited(DP)

本文探讨了一种区间覆盖问题,目标是最小化每个整点被覆盖的权值和的最大值。通过动态规划方法,对带权区间的右端点进行排序,并设计状态转移方程,实现了高效求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

链接:https://ac.nowcoder.com/acm/contest/142/B
来源:牛客网
 

题目描述

Chiaki has a long interval [1,m] and n small intervals [l1, r1], [l2,r2], ..., [ln, rn]. Each small interval [li,ri] is associated with a weight wi.
Chiaki would to select some small intervals such that:

  • each integer position x ∈ [1, m] is covered by at least one small interval.
  • let sx be the sum of the weights of all the small intervals covering position x, the maximum value of sx should be minimum.

Chiaki would like to know the minimum value of maximum sx.

输入描述:

There are multiple test cases. The first line of input contains an integer T, indicating the number of test
cases. For each test case:
The first line contains two integers n and m (1 ≤ n, m ≤ 2000) -- the number of small intervals and the length of the long interval.
Each of the next n lines contains three integers li, ri and wi (1 ≤ li ≤ ri ≤ m, 1 ≤ wi ≤ 1000).
It is guaranteed that the sum of all n does not exceed 20000.

输出描述:

For each test case, output an integer denoting the answer, or -1 if Chiaki cannot select such intervals.

 

输入

2
2 4
1 2 2
3 4 5
1 4
1 3 1

输出

5
-1

 

题意:

给你n个带权区间,要求选择若干区间覆盖[1, m]内的所有整点,使得每个整点被覆盖权值和的最大值最小

 

思路:

可以猜一下:每个点最多被两个区间覆盖,那么就可以按照所有区间右端点排序,

然后设dp[i][x]为只考虑前i个区间,第i个区间必选,其中位置x处已经被两个区间所覆盖的最优解

直接n²暴力转移就好了

具体看代码,下面注释中有一个很强的样例

 

//https://ac.nowcoder.com/acm/contest/142/B
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<map>
#include<string>
#include<math.h>
#include<queue>
#include<stack>
#include<iostream>
using namespace std;
#define LL long long
#define mod 1000000007
int dp[2005][2005];
typedef struct Res
{
	int l, r, val;
	bool operator < (const Res &b) const
	{
		if(r<b.r || r==b.r && l<b.l)
			return 1;
		return 0;
	}
}Res;
Res s[2005];
int main(void)
{
	int T, n, m, i, j, ans;
	scanf("%d", &T);
	while(T--)
	{
		scanf("%d%d", &n, &m);
		for(i=0;i<=n;i++)
		{
			if(i!=0)
				scanf("%d%d%d", &s[i].l, &s[i].r, &s[i].val);
			for(j=0;j<=m;j++)
				dp[i][j] = 1044266558;
		}
		sort(s+1, s+n+1);
		dp[0][0] = 0;
		for(i=1;i<=n;i++)
		{
			for(j=1;j<=i-1;j++)
			{
				if(s[j].r+1<s[i].l || s[j].l>=s[i].l)
					continue;
				if(s[j].r+1==s[i].l)
					dp[i][s[j].r] = min(dp[i][s[j].r], max(dp[j][s[j].r], s[i].val));
				else if(s[j].r+1>s[i].l)
					dp[i][s[j].r] = min(dp[i][s[j].r], max(dp[j][s[i].l-1], s[i].val+s[j].val));
			}
			if(s[i].l==1)
				dp[i][0] = s[i].val;
			for(j=1;j<=s[i].r;j++)
				dp[i][j] = min(dp[i][j], dp[i][j-1]);
		}
		ans = 1044266558;
		for(i=1;i<=n;i++)
		{
			if(s[i].r==m)
				ans = min(ans, dp[i][m]);
		}
		if(ans==1044266558)
			printf("-1\n");
		else
			printf("%d\n", ans);
	}
	return 0;
}
/*
1
3 5
1 3 3
2 4 1
3 5 3
*/

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值