LGOJ 普及+/提高 动态规划题2019-9-1选做

P1133 教主的花园

题目链接

LGOJ P1133 教主的花园

解题思路

显而易见是一道线性DP
我一开始想的是两维状态,即 f [ i ] [ j ] f[i][j] f[i][j]表示考虑了前 i i i颗树,第 i i i棵树是第 j j j类的树(其中 j ∈ { 0 , 1 , 2 } j\in\{0, 1, 2\} j{0,1,2},分别表示高度为10, 20, 30的树)
但是,还有个东西没有考虑,那就是我们这第 i i i棵树是处于树高的波峰还是波谷呢?于是再加上:
f [ i ] [ j ] [ 0 / 1 ] f[i][j][0/1] f[i][j][0/1]表示考虑了前 i i i颗树,第 i i i棵树是第 j j j类的树(其中 j ∈ { 0 , 1 , 2 } j\in\{0, 1, 2\} j{0,1,2},分别表示高度为10, 20, 30的树),且第 i i i棵树的树高是在相邻的两棵树的波峰(0)还是波谷(1)
另外,由于连成的是一个环,我们要特判1和n两个位置,跑三次dp就好了。
大致如此

详细代码

#define USEFASTREAD 0

#include<cstdio>
#define inl inline
#define rg register
#define Rep(i, s, t) for(rg int i = s; i <= t; i++)
#define Repd(i, t, s) for(rg int i = t; i >= s; i--)
#define putln putchar('\n')
#define putsp putchar(' ')
typedef long long ll;
#if USEFASTREAD
char In[1 << 20], *ss = In, *tt = In;
#define getchar() (ss == tt && (tt = (ss = In) + fread(In, 1, 1 << 20, stdin), ss == tt) ? EOF : *ss++)
#endif
namespace IO {
	void RS() {freopen("test.in", "r", stdin); freopen("test.out", "w", stdout);}
	inl ll read() {
		ll x = 0, f = 1; char ch = getchar();
		for(; ch < '0' || ch > '9'; ch = getchar()) if(ch == '-') f = -1;
		for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
		return x * f;
	}
	inl void write(ll x) {
		if(x < 0) {x = -x; putchar('-');}
		if(x >= 10) write(x / 10);
		putchar('0' + x % 10);
	}
	inl void writeln(ll x) {write(x); putln;}
	inl void writesp(ll x) {write(x); putsp;}
}
using namespace IO;
template<typename T> inl T Max(const T& x, const T& y) {return x < y ? y : x;}
template<typename T> inl T Min(const T& x, const T& y) {return x < y ? x : y;}
template<typename T> inl void Swap(T& x, T& y) {T t = x; x = y; y = t;}
template<typename T> inl T Abs(const T& x) {return x < 0 ? -x : x;}
#include<cstring>
const int MAXN = 1e6 + 5;
int n; 
ll f[MAXN][3][2]; //种到第i棵树,种类是j,是波峰(k = 0) 或 波谷(k = 1) 
ll v[MAXN][3];
ll ans;
int main() {
	n = read();
	for(rg int i = 1; i <= n; i++)
		v[i][0] = read(), v[i][1] = read(), v[i][2] = read();
	for(rg int firj = 0; firj < 3; firj++) {//枚举第一颗种啥 
		memset(f, 0x00, sizeof f);
		f[1][firj][0] = f[1][firj][1] = v[1][firj];
		for(rg int i = 2; i <= n; i++) 
			for(rg int j = 0; j < 3; j++) {
				ll &f0 = f[i][j][0], &f1 = f[i][j][1];
				ll &nv = v[i][j];
				for(rg int lj = 0; lj < j; lj++) {//上一次种的是波谷(k = 1),这一次种的是波峰(k = 0)
					f0 = Max(f0, f[i - 1][lj][1] + nv);
				} 
				for(rg int lj = j + 1; lj < 3; lj++) {
					f1 = Max(f1, f[i - 1][lj][0] + nv);
				}
			}
		for(rg int j = 0; j < firj; j++) //1是波峰(k = 0),现在是波谷(k = 1)
			ans = Max(ans, f[n][j][1]);
		for(rg int j = firj + 1; j < 3; j++)
			ans = Max(ans, f[n][j][0]);
	}
	write(ans);
	return 0;		
}

P1279 字串距离

题目链接

LGOJ P1279 字串距离

解题思路

我们易设状态为 f [ i ] [ j ] f[i][j] f[i][j]匹配A串前 i i i个字符和B串前 j j j个字符所得到的距离。
那么易得转移方程:
f [ i ] [ j ] = m a x { f [ i − 1 ] [ j ] + K − − − − − − − i f   A [ i ] 放 空 格 f [ i ] [ j − 1 ] + K − − − − − − − i f   B [ i ] 放 空 格 f [ i − 1 ] [ j − 1 ] + a b s ( A [ i ] − B [ i ] ) − − 直 接 匹 配 f[i][j]=max\left\{\begin{matrix} f[i-1][j] + K-------if\ A[i]放空格\\ f[i][j-1]+K-------if\ B[i]放空格\\ f[i-1][j-1]+abs(A[i]-B[i])--直接匹配 \end{matrix}\right. f[i][j]=maxf[i1][j]+Kif A[i]f[i][j1]+Kif B[i]f[i1][j1]+abs(A[i]B[i])
注意边界!

详细代码

#define USEFASTERREAD 0

#define rg register
#define inl inline
#define DEBUG printf("qwq\n")
#define DEBUGd(x) printf("var %s is %lld", #x, ll(x))
#define DEBUGf(x) printf("var %s is %llf", #x, double(x))
#define putln putchar('\n')
#define putsp putchar(' ')
#define Rep(a, s, t) for(rg int a = s; a <= t; a++)
#define Repdown(a, t, s) for(rg int a = t; a >= s; a--)
typedef long long ll;
typedef unsigned long long ull;
#include<cstdio>

#if USEFASTERREAD
char In[1 << 20], *ss = In, *tt = In;
#define getchar() (ss == tt && (tt = (ss = In) + fread(In, 1, 1 << 20, stdin), ss == tt) ? EOF : *ss++)
#endif
namespace IO {
	inl void RS() {freopen("test.in", "r", stdin), freopen("test.out", "w", stdout);}
	inl ll read() {
		ll x = 0, f = 1; char ch = getchar();
		for(; ch < '0' || ch > '9'; ch = getchar()) if(ch == '-') f = -1;
		for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + int(ch - '0');
		return x * f;
	}
	inl void write(ll x) {
		if(x < 0) {putchar('-'); x = -x;}
		if(x >= 10) write(x / 10);
		putchar(x % 10 + '0');
	}
	inl void writeln(ll x) {write(x), putln;}
	inl void writesp(ll x) {write(x), putsp;}
}
using namespace IO;
template<typename T> inline T Max(const T& x, const T& y) {return y < x ? x : y;}
template<typename T> inline T Min(const T& x, const T& y) {return y < x ? y : x;}
template<typename T> inline void Swap(T& x, T& y) {T tmp = x; x = y; y = tmp;}
template<typename T> inline T Abs(const T& x) {return x < 0 ? -x : x;}
#include<cstring>
const int MAXLEN = 2005;
const int INF = 0x3f3f3f3f;
char A[MAXLEN], B[MAXLEN];
int n, m;
int K;
int f[MAXLEN][MAXLEN];

int main() {
	//RS();
    scanf("%s", A + 1);
    scanf("%s", B + 1);
    K = read();
    n = strlen(A + 1); m = strlen(B + 1);
    memset(f, 0x3f, sizeof f);
    f[0][0] = 0;
    for(rg int i = 1; i <= n; i++) f[i][0] = i * K;
    for(rg int i = 1; i <= m; i++) f[0][i] = i * K;
    for(rg int i = 1; i <= n; i++)
        for(rg int j = 1; j <= m; j++) {
            f[i][j] = Min(f[i][j], f[i - 1][j] + K);
            f[i][j] = Min(f[i][j], f[i][j - 1] + K);
            f[i][j] = Min(f[i][j], f[i - 1][j - 1] + Abs(A[i] - B[j]));
        }
    writeln(f[n][m]);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

日居月诸Rijuyuezhu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值