zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    组合博弈入门
    模拟练1
    鼠标点击 input,显示瞬间的边框颜色,对之修改与隐藏
    display: inline-block兼容性写法
    background-clip与background-origin两者的区别
    article标签和aside标签两者的理解
    jQuery插件实现左右无缝轮播
    JS面向对象基础2
    JS面向对象基础1
    CSS3的基础知识点
  • 原文地址:https://www.cnblogs.com/wlw-x/p/12815273.html
Copyright © 2011-2022 走看看