zoukankan      html  css  js  c++  java
  • DP训练——1

    DP刷题笔记——1

    序列最大收益(中兴笔试)

    题目描述

    给定一个长度为 \(m\) 的整数序列 \(a_1...a_n\)

    序列中每个元素的值 \(a_i\) 均满足 \(1 \leq a_i \leq n\)

    当一个值为 \(i\) 的元素和一个值为 \(j\) 的元素相邻时,可以产生的收益为 \(w_{i,j}\)

    现在,我们可以从序列中删除最多 \(k\) 个元素,删除一些元素后,原本不相邻的元素可能会变得相邻。

    序列的收益和为所有相邻元素对产生的收益之和,例如一个长度为 3 的整数序列 1,3,2 的收益和为 \(w_{1,3} + w_{3,2}\)

    请问,通过利用删除操作,能够得到的序列的最大收益和是多少?

    数据范围

    \(1 \leq n,k,m \leq 200,0 \leq w_{i,j} \leq 10^7,1 \leq a_i \leq n\)

    分析

    很容易的可以考虑到设\(f_{i,j}\)为处理前\(i\)个数,删除了\(j\)个数的最大收益,考虑转移

    转移的时候我们需要枚举与第\(i\)个位置相邻的是哪个位置,设为\(u\),则\(u -> i\)中会被删除\(i - u - 1\)个值,且\(u\)前会删除\(j - (i - u - 1)\)个值,那么\(f[i][j] = max(f[i][j],f[u][j - (i - u - 1)] + w[a[u]] + a[i])\)

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 210;
    
    int f[N][N];
    int ans = -1;
    int n,k,m;
    int a[N];
    int w[N][N];
    int main () {
    	cin >> n >> k >> m;
    	for(int i = 1;i <= m; ++i) cin >> a[i];
    	for(int i = 1;i <= n; ++i) {
    		for(int j = 1;j <= n; ++j) {
    			cin >> w[i][j];
    		}
    	}
    	memset(f,-0x3f,sizeof f);
    	f[1][0] = 0;
    	for(int i = 1;i <= m; ++i) {
    		for(int j = 0;j <= k; ++j) {
    			for(int l = 1;l < i; ++l) {
    				if(j - (i - l - 1) >= 0) {
    					f[i][j] = max(f[i][j],f[l][j - (i - l - 1)] + w[a[l]][a[i]]);
    				}
    			}
    		}
    	}
    	for(int i = 0;i <= k; ++i) ans = max(ans,f[m][i]);
    	cout << ans << endl;
    	return 0;
    }
    

    调研(UPC训练平台)

    题目描述

    有一直线型展台共有 \(m\) 个展位,按该展位离入口处的远近顺序编号,其编号分别为 \(1...m\);其中只有 $n $个是展示新技术的展位,最后一个展示新技术的展位编号为 m。
    这次调研分两个小组进行,每个小组最多调研连续的 10 个展位,且每个小组调研的展位至少相隔 2 个展位。
    乐乐希望你设计一种安排方案,使领导调研更多的展示新技术的展位。

    数据范围

    \(1 \leq n \leq m \leq 10^5\)

    分析

    法一:

    ​ 设\(f_{i,j}\)表示处理到前\(i\)个展位,已经安排了0/1/2个小组的最大方案。

    ​ 则\(f[i][1] = max(f[i - 1][1],s[i] - s[i - k]),f[i][2] = max(f[i - 1][2],f[i - j - 2][1] + s[i] - s[i - j])\)

    ​ 注意:当\(i=1\)时,\(i - j \geq 2\)这个条件不会触发,但是\(f_{i,2}\)也需要拷贝转移,应将其提到前面来转移。

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 1e5 + 10;
    int n;
    int f[N][3];
    int a[N];
    int s[N];
    int ans;
    int mx = -1;
    int main () {
        //freopen("a.in","r",stdin);
        cin >> n;
        for(int i = 1;i <= n; ++i) {
            cin >> a[i];
            mx = max(mx,a[i]);
        }
        for(int i = 1;i <= n; ++i) s[a[i]] = 1;
        for(int i = 1;i <= mx; ++i) s[i] += s[i - 1];
        for(int i = 1;i <= mx; ++i) {
            for(int k = 0;k <= 10; ++k) {
                if(i - k >= 0) {
                    f[i][1] = max(f[i - 1][1],s[i] - s[i - k]);
                }
            }
            f[i][2] = f[i - 1][2]; //自闭了!!!
            for(int j = 0;j <= 10 and i - j >= 2; ++j) {
                f[i][2] = max(f[i][2],f[i - j - 2][1] + s[i] - s[i - j]);
            }
        }
        for(int i = 0;i <= mx; ++i) ans = max(ans,f[i][2]);
        cout << ans << endl;
        return 0;
    }
    /**************************************************************
        Problem: 19283
        User: 2020UJN17
        Language: C++
        Result: 正确
        Time:50 ms
        Memory:3976 kb
    ****************************************************************/
    

    法二:

    ​ 首先枚举框,处理出每个框的价值后排序,对于每个框找一个与其在\([L - 2,R + 2]\)不相交的最大框,最多不超过225个,卡空间。

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 100001;
    int ans;
    int n;
    int s[N]; 
    struct node {
        int l;
        int r;
        int sum;
    }a[100 * N];
    int cnt;
    int mx = -1;
    bool cmp(node a,node b) {
        if(a.sum == b.sum) {
            return a.r > b.r;
        }
        return a.sum > b.sum;
    }
    int main () {
        cin >> n;
        for(int i = 1;i <= n; ++i) {
            int x;
            cin >> x;
            s[x] = 1;
            mx = max(mx,x);
        }
        for(int i = 1;i <= mx + 20; ++i) s[i] += s[i - 1];
        for(int k = 1;k <= 10; ++k) {
            for(int i = 1;i <= mx - k + 1; ++i) {
                int r = i + k - 1;
                if(r <= mx) {
                    a[++cnt].l = i;
                    a[cnt].r = r;
                    a[cnt].sum = s[r] - s[i - 1];
                }
            }
        }
        sort(a + 1,a + cnt + 1,cmp);
        for(int i = 1;i <= cnt; ++i) {
            int L = a[i].l;
            int R = a[i].r;
            for(int j = 1;j <= cnt; ++j) {
                int l = a[j].l;
                int r = a[j].r;
                if(r < L - 2 or l > R + 2) {
                    ans = max(ans,a[i].sum + a[j].sum);
                    break;
                }
            }
            //cout << a[i].sum << endl;
        }
        cout << ans << endl;
        return 0;
    }
    /**************************************************************
        Problem: 19283
        User: 2020UJN17
        Language: C++
        Result: 正确
        Time:466 ms
        Memory:119608 kb
    ****************************************************************/
    

    Adventurer’s Guild(山东省赛)

    题目描述

    Yuna traveled into the fantasy world. The gods of this world gave her a powerful set of equipment so that she could defeat many fierce monsters. However, she had limited health points and stamina, and she could not kill a large number of monsters.

    Adventurer's guild would release \(n\) monster crusade missions, such as black python and wild wolf. Completing the \(i-th\) mission would consume Yuna \(h_i\) health points and \(s_i\) stamina, and then she would get \(w_i\) gold coins.

    In the beginning, Yuna had \(H\) health points and \(S\) stamina. When her health points were dropped to less than or equal to \(0\), she would die. However, when her stamina was dropped to less than \(0\), she would not give up, and then the overdrawn stamina would be reduced from health points. For example, her health points would be reduced by \(3\), when her stamina dropped to \(-3\), and then her stamina would be reset to \(0\). If her health points can not afford the overdrawn stamina, she would also die.

    As a friend of Yuna, can you help her choose some missions to complete to get the maximum number of gold coins? Make sure Yuna does not die, or you will be very sad.

    数据范围

    \(1 \leq n \leq 1000,1 \leq H \leq 300,0 \leq S \leq 300,0 \leq h_i,s_i \leq 300,1 \leq w_i \leq 10^9\)

    分析

    有依赖的背包问题,设\(f[i][j][k]\)表示处理将前\(i\)个物品塞进背包1、背包2的最大收益。

    因为耐力见底损血,特判一下。

    最后加一个滚动数组优化。

    #include <bits/stdc++.h>
    using namespace std;
    const int INF = 0x3f3f3f3f;
    const int N = 1010;
    #define ll long long
    int h[N];
    int s[N];
    int w[N];
    ll f[310][310];
    ll ans = 0;
    int n,H,S;
    int res = 0;
    int main () {
    	cin >> n >> H >> S;
    	for(int i = 1;i <= n; ++i) {
    		scanf("%d %d %d",&h[i],&s[i],&w[i]);
    	}
    	
    	memset(f,0,sizeof f);
    	
    	for(int i = 1;i <= n; ++i) {
    		for(int j = H;j >= h[i]; --j) {
    			for(int k = S; k >= 0;--k) {
    				if(j > h[i]) {
    					if(k - s[i] < 0) {
    						if(j - s[i] + k - h[i] > 0)
    							f[j][k] = max(f[j][k],f[j - (s[i] - k) - h[i]][0] + w[i]);
    					}
    					else f[j][k] = max(f[j][k],f[j - h[i]][k - s[i]] + w[i]);
    				}
    			}
    		}
    	}
    	for(int i = 1;i <= H; ++i) {
    		for(int j = 0;j <= S; ++j) {
    			ans = max(ans,f[i][j]);
    		}
    	}
    	
    	cout << ans << endl;
    	return 0;
    }
    
    

    Parsa's Humongous Tree

    题目描述

    给定一个树,每个节点可以选的值为\([l_i,r_i]\)之间的一个值,求如何安排数值可以使得\(\sum_{u,v \in T} |a_u - a_v|\)最大,输出最大值。

    数据范围

    \(\sum n \leq 10^5,T \leq 250,1 \leq l_i,r_i \leq 10^9\)

    分析

    对于任意连接的一个点对\((u,v)\)来说,最大值一定出现在端点处,我们考虑设\(f_{i,0/1}\)表示当处理到第\(i\)个节点时,当前节点选\(l_i\)\(r_i\)的最大收益,转移为:

    f[u][0] += max(f[v][0] + abs(l[u] - l[v]),f[v][1] + abs(l[u] - r[v]));
    f[u][1] += max(f[v][0] + abs(r[u] - l[v]),f[v][1] + abs(r[u] - r[v]));
    

    开个\(long \; \;long\)

    #include <bits/stdc++.h>
    using namespace std;
    #define ll long long
    const int N = 1e5 + 10;
    ll f[N][2];//选上界,or选下界
    
    struct edge {
    	int to;
    	int nxt;
    }e[N << 1];
    int cnt;
    int head[N];
    void add (int u,int v) {
    	e[++cnt].to = v;
    	e[cnt].nxt = head[u];
    	head[u] = cnt;
    	return;
    }
    
    void Addtree(int u,int v) {
    	add(u,v),add(v,u);
    }
    int T;
    int n;
    int l[N],r[N];
    
    void dfs(int x,int fa) {
    	for(int i = head[x];i;i = e[i].nxt) {
    		int y = e[i].to;//cout << "#:" << y << endl;
    		if(y == fa) continue;
    		dfs(y,x);
    		f[x][0] += max(f[y][0] + abs(l[x] - l[y]),f[y][1] + abs(r[y] - l[x]));
    		f[x][1] += max(f[y][0] + abs(r[x] - l[y]),f[y][1] + abs(r[y] - r[x]));
    	}
    }
    
    
    int main () {
    	ios :: sync_with_stdio(false);
    	cin >> T;
    	while(T --) {
    		cin >> n;
    		for(int i = 1;i <= n; ++i) cin >> l[i] >> r[i];
    		cnt = 0;
    		memset(head,0,sizeof head);
    		memset(f,0,sizeof f);
    		for(int i = 1;i < n; ++i) {
    			int u,v;
    			cin >> u >> v;
    			Addtree(u,v);
    		}
    		dfs(1,0);
    		//cout << "#:" << endl;
    		//for(int i = 1;i <= n; ++i) cout << f[i][0] << ' ' << f[i][1] << endl;
    		cout << max(f[1][0],f[1][1]) << endl;
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    cocos2d-x的初步学习七
    cocos2d-x的初步学习六
    cocos2d-x的初步学习五
    cocos2d-x的初步学习四
    net core or Linux
    XML序列化反序列化
    用NSoup解析HTML
    ubuntu 下的ftp安装及root身份远程配置
    Windows 10 子系统Linux重启(不重启Win10)
    C# HttpRequest 请求
  • 原文地址:https://www.cnblogs.com/akoasm/p/14778059.html
Copyright © 2011-2022 走看看