DP+思维

DP+思维

Codeforces Round #765 (Div. 2) C
因为期末考试,很久没有打题了,这是寒假复健训练外加dp苦手的救赎

题意:

给n个限速牌,每个限速牌写上ai,表示经过本限速牌后今后每公里限制走ai单位的时间。
再给定每个牌的位置。
求至多去除k个牌能花的最短时间
其中不可以去除在位置0处的第一个牌,因为它给定了初始速度

解法:

起初想的贪心暴力过,但是不太行,就当练习链表了
然后是dp
考虑dp[i][j]表示从第i个牌子开始走到最后,切掉j个牌儿(不包括自己)花的最短时间

丢脸:

因为每个牌走到终点花的时间是依赖后面的牌子的,所以从尾到头遍历第一层
然后根据当前的起点牌,枚举拆了几个牌后,到了下一个没有被拆掉的牌,这样可以包含所有的方案

#include<bits./stdc++.h>
#define ll long long
#define mes(a,b) memset(a,b,sizeof(a))
#define ctn continue
#define ull unsigned long long
#pragma warning(disable:4996)
#define tgg cout<<"---------------"<<endl;
const ll linf = 9223372036854775807;
const int inf = 0x3f3f3f3f;
using namespace std;
const double pi = acos(-1);
const ll maxn = 2e5 + 4;
const int mod = 31011;
const double eps = 1e-8;
const ull p = 131;
const ull pc = 13331;
inline ll gcd(int a, int b) {
	while (b ^= a ^= b ^= a %= b);
	return a;
}

int pos[502];
int val[502];
int dp[502][502];// 第i个牌子开始拆j个牌子最短时间

int main() {
	mes(dp, inf);
	int n, m, k;
	cin >> n >> m >> k;
	for (int i = 1; i <= n; i++) {
		cin >> pos[i];
	}
	for (int i = 1; i <= n; i++) {
		cin >> val[i];
	}
	pos[n + 1] = m;
	dp[n + 1][0] = 0;
	// 从尾到头遍历牌
	for (int i = n; i >= 1; i--) {
		// 今后拆掉j个牌,最多n-i个
		for (int j = 0; j <= n - i; j++) {
			// 假设第l个牌是第一个没有被拆的牌,那么前面全拆
			for (int l = 0; l <= j; l++) {
				dp[i][j] = min(dp[i][j], val[i] * (pos[i + l + 1] - pos[i]) + dp[i + l + 1][j - l]);
			}
		}
	}
	int ans = inf;
	for (int i = 0; i <= k; i++) {
		ans = min(ans, dp[1][i]);
	}
	cout << ans << endl;
	return 0;
}
上一篇:C# 优化程序的四十七种方法


下一篇:C#中的迭代器