Daliy Algorithm (线性dp)-- day 70

Nothing to fear


种一棵树最好的时间是十年前,其次是现在!

那些你早出晚归付出的刻苦努力,你不想训练,当你觉的太累了但还是要咬牙坚持的时候,那就是在追逐梦想,不要在意终点有什么,要享受路途的过程,或许你不能成就梦想,但一定会有更伟大的事情随之而来。 mamba out~

2020.5.1


人一我十, 人十我百,追逐青春的梦想,怀着自信的心,永不言弃!

摆花

值得注意的是,如果采用记忆化搜索的策略,如果存在剪枝一定是剪枝先放在前面,在进行返回值

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <vector>
#include <cstring>

using namespace std;
const int N = 105;
const int mod = 1000007;
int f[N][N];
int a[N];
int n , m;
// x 表示从第 X 当中取选择
// y 剩余可摆放的数量
int dfs(int x,int y)
{
	if(y == 0)return 1;
	if(y < 0 || x > n)return 0;
	if(f[x][y] != -1)return f[x][y];
	int sum = 0;
	for(int i = 0;i <= a[x] ;i ++)
	{
		sum = (sum + dfs(x + 1 , y - i)) % mod;
	}
	return f[x][y] = sum % mod;
}

void dp()
{
	//f[i][j] 表示前i种花摆放了 j 盆的方案数
	f[0][0] = 1;
	for(int i = 1;i <= n ;i ++)
	{
		for(int j = 0;j <= m ;j ++)
		{
			for(int k = 0;k <= min(j , a[i]);k ++)
			{
				f[i][j] = (f[i][j] + f[i-1][j-k]) % mod;
			}
		}
	}
	cout << f[n][m] << endl;
}
int main()
{
 	cin >> n >> m;
	for(int i = 1;i <= n ;i ++)scanf("%d",&a[i]);
	dp();
	return 0;
}

合唱队形

左边最长上升子序列 右边最长下降子序列
枚举从每一个位置开始,其从 1 - k 的最长上升子序列的最大值
从 k + 1 - n的最长下降子序列的最大值

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <cstring>

using namespace std;
const int N = 105;
int n;
int h[N];
int f[N];
void dp()
{
	int ans = 0;
	for(int k = 1;k <= n ; k++)
	{
		memset(f , 0 , sizeof f);
		int a = 0, b = 0;
		for(int i = 1;i <= k;i ++)
		{
			f[i] = 1;
			for(int j = 1;j < i ;j ++)
			{
				if(h[j] < h[i])
					f[i] = max(f[j] + 1,f[i]);
			}
			a = max(a , f[i]);
		}
		for(int i = k + 1;i <= n ;i ++)
		{
			f[i] = 1;
			for(int j = k + 1;j < i;j ++)
			{
				if(h[j] > h[i])
					f[i] = max(f[j] + 1,f[i]);
			}
			b = max(b , f[i]);
		}
		ans = max(ans , a + b);
	}
	cout << n - ans << endl;
}
int main()
{
	cin >> n;
	for(int i = 1;i <= n ;i ++)cin >> h[i];
	dp();
	return 0;
}

导弹拦截

主要还是二分的过程要卡好边界

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>

using namespace std;
const int N = 100005;
int n;
int f[N],g[N],h[N];
int main()
{
	while(~scanf("%d",&h[++n]));n--;
	int len = 1;
	// 求一个最长不上升子序列
	memset(f , 0x3f3f3f3f ,sizeof f);
	f[1] = h[1];
	for(int i = 2;i <= n ;i ++)
	{
		if(h[i] <= f[len])f[++len] = h[i];
		else{
			int l = 0,r = len;
			while(l < r)
			{
				int mid = l + r >> 1;
				if(f[mid] >= h[i])l = mid + 1;
				else r = mid;
			}
			f[l] = max(f[l],h[i]);
		}
	}
	cout << len << endl;
	// 求最长上升子序列的长度
	memset(f , 0x3f3f3f3f , sizeof f);
	f[1] = h[1];len = 1;
	for(int i = 2;i <= n ;i ++)
	{
		if(h[i] > f[len])f[++len] = h[i];
		else{
			int l = 1,r = len;
			while(l < r)
			{
				int mid = l + r >> 1;
				if(f[mid] >= h[i])r = mid;
				else l = mid + 1;
			}
			f[l] = min(f[l],h[i]);
		}
	}
	cout << len << endl;
	return 0;
}

LCS

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstdlib>

using namespace std;
const int N = 100005;
const int MAX = 0x3f3f3f3f;
int a[N] ,b[N],map[N],f[N] , n;
int main()
{
	cin >> n;
	for(int i = 1;i <= n ;i ++)
	{
		scanf("%d",&a[i]);
		// 记录a中每个元素出现的位置
		map[a[i]] = i;
	}
	for(int i = 1;i <= n ;i ++)
	{
		scanf("%d",&b[i]);
		f[i] = MAX;
	}

	int len = 0;f[0] = 0;
	for(int i = 1;i <= n ;i ++)
	{
		int l = 0, r = len;
		if(map[b[i]] > f[len])f[++len] = map[b[i]];
		else
		{
			while(l < r)
			{
				int mid = l + r >> 1;
				if(f[mid] > map[b[i]])r = mid;
				else l = mid + 1;
			}
			f[l] = min(map[b[i]],f[l]);
		}
	}
	cout << len << endl;
	return 0;
}
posted @ 2020-05-01 23:00  _starsky  阅读(110)  评论(0编辑  收藏  举报