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;
}