1. 程式人生 > >牛客網暑期ACM多校訓練營(第四場): B. Interval Revisited(DP)

牛客網暑期ACM多校訓練營(第四場): B. Interval Revisited(DP)

題目描述

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
*/