zoukankan      html  css  js  c++  java
  • luogu 【动态规划1】动态规划的引入

    P1216 数字三角形

    每个节点的值只受左上,右上两节点影响。索引从1开始,避免处理边界问题。

    int n,ans,a[1005][1005],dp[1005][1005];
    //pull: dp[i][j] = max(dp[i - 1][j - 1], dp[i - 1][j]) + dp[i][j]; 
    int main(void){
    	ios::sync_with_stdio(false);
    	cin.tie(0);cout.tie(0);
    	cin >> n;
    	for(int i = 1; i <= n; i++){
    		for(int j = 1; j <= i; j++) cin >> dp[i][j];
    	}
    	for(int i = 1; i <= n; i++){
    		for(int j = 1; j <= i;j++) dp[i][j] = max(dp[i - 1][j - 1], dp[i - 1][j]) + dp[i][j];
    	}
    	for(int i = 1; i <= n; i++) ans = max(ans, dp[n][i]);
    	cout << ans;	
    	return 0;
    }
    
    P1434 滑雪

    一个二维数组,每个数字代表当前点的高度,可以上下左右移动且只可以由高的点移动到低的点,找出最大移动次数 -- 记忆化搜索。

    int n,m,ans,d[110][110],h[110][110],dir[2][4] = {-1,1,0,0,0,0,-1,1};
    //d[x][y]记录(x,y)的最大移动次数 
    int dfs(int x,int y){
    	if(d[x][y]) return d[x][y];
    	d[x][y] = 1;//最小下滑次数为1 
    	for(int i = 0; i < 4; i++){
    		int tx = x + dir[0][i];
    		int ty = y + dir[1][i];
    		if(h[tx][ty] > h[x][y]) d[x][y] = max(d[x][y], dfs(tx, ty) + 1);
    	}
    	return d[x][y];
    }
    int main(void){
    	ios::sync_with_stdio(false);
    	cin.tie(0);cout.tie(0);
    	cin >> n >> m;
    	for(int i = 1; i <= n; i++){
    		for(int j = 1; j <= m; j++) cin >> h[i][j];
    	}
    	for(int i = 1; i <= n; i++){
    		for(int j = 1; j <= m; j++) ans = max(ans, dfs(i,j));
    	}	
    	cout << ans;
    	return 0;
    }
    
    P2196 挖地雷

    n个地窖,每个地窖中有若干个地雷,地窖间的连接情况已给出,设计一个挖出地雷最多的方案。

    • n <= 20,可以直接暴力...
    • 思路同最长上升子序列,dp[i]表示以i为终点时挖到的最大地雷数
    • 枚举i之前的所有的地窖,与i连接时,判断是否可以通过这个地窖挖取更多的地雷,pre数组记录各节点的前驱,更新dp数组的同时,更新相应的前驱。
    int n,m,ans,t,idx,dp[110],link[25][25],w[25],pre[25];
    void print(int i){
    	if(pre[i]) print(pre[i]);
    	cout << i << ' ';
    }
    int main(void){
    	ios::sync_with_stdio(false);
    	cin.tie(0);cout.tie(0);
    	cin >> n;
    	for(int i = 1; i <= n; i++) cin >> w[i];
    	for(int i = 1; i <= n - 1; i++){
    		for(int j = i + 1; j <= n; j++) cin >> link[i][j];
    	}
    	dp[1] = w[1];
    	for(int i = 2; i <= n; i++){
    		dp[i] = w[i];
    		for(int j = 1; j < i; j++){
    			if(link[j][i] && dp[i] < dp[j] + w[i]){
    				dp[i] = dp[j] + w[i];
    				pre[i] = j;
    			}
    		}
    		if(dp[i] > ans){
    			ans = dp[i];
    			t = i;
    		}
    	}
    	print(t);
    	cout << endl << ans;
    	return 0;
    }
    
    P4017 最大食物链计数

    n类生物,m种关系,求最大食物链数量mod 80112002的值。n个点组成了有m条边的DAG --> 入度为0的点到出度为0的点之间路径的个数 --> 可以用拓扑排序 or 记忆化搜索

    • 拓扑排序:
      1. num数组记录各节点权值,初始入度为0的点权值为1,删除这些节点时,将权值加到所有相邻的节点上。
      2. 排序结束后,统计出度为0的节点的权值和
    int n,m,a,b,idx,ans,in[5005],out[5005],h[5005],num[5005];//in out 记录个点出度 入度 
    const int mod = 80112002, kN = 5e5 + 5;
    struct node{
    	int e,ne;
    }edges[kN];
    void add(int a, int b){//s -> e
    	edges[idx].e = b;
    	edges[idx].ne = h[a];
    	h[a] = idx++;
    }
    int main(void){
    	ios::sync_with_stdio(false);
    	cin.tie(0);cout.tie(0);
    	memset(h, -1, sizeof h);
        
    	cin >> n >> m;
    	for(int i = 0; i < m; i++){
    		cin >> a >> b;
    		add(a, b);
    		++out[a];
    		++in[b];
    	}
    	queue<int> q;
    	for(int i = 1; i <= n; i++){
    		if(in[i] == 0){//入度为0的点入队 
    			num[i] = 1,q.push(i); 
    		}
    	}
    	while(!q.empty()){
    		int top = q.front();
    		q.pop();
    		//删除top,相邻点入度-1 
    		for(int i = h[top]; i != -1; i = edges[i].ne){
    			--in[edges[i].e];
    			num[edges[i].e] = (num[edges[i].e] + num[top]) % mod;
    			if(in[edges[i].e] == 0) q.push(edges[i].e);  
    		}  
    	}
    	//搜索出度为0的点,计算答案 
    	for(int i = 1; i <= n; i++){
    		if(!out[i]) ans = (ans + num[i]) % mod;
    	}
    	cout << ans;
    	return 0;
    }
    
    • 记忆化搜索
      1. 入度为0的节点:起点,出度为0的节点:终点
      2. 搜索到终点即为一条最长食物链。
      3. dp[i]表示i到终点有多少条路径,搜索时存在dp[i],返回相应值
      4. 搜索所有的起点,结果求和取模。
    P1048 采药

    裸01背包,dp(i,j)表示前i株药材采摘耗时为j的最大价值。由于i状态只与i - 1状态有关,可使用滚动数组优化,dp[i]表示耗时为i时的最大价值.

    #include<iostream>
    #include<algorithm>
    #define endl '
    '
    using namespace std;
    int n,m,ans,dp[1010],t,w;
    //int t[110],w[110];
    int main(void){
    	ios::sync_with_stdio(false);
    	cin.tie(0);cout.tie(0);
    	cin >> n >> m;
    	for(int i = 0; i < m; i++){
    		cin >> t >> w;
    		for(int j = n; j >= t; j--){//大-小枚举,只可使用一次 
    			dp[j]  = max(dp[j], dp[j - t] + w);
    		}
    	}
    	cout << dp[n];
    	/*
    	for(int i = 1; i <= m; i++) cin >> t[i] >> w[i];
    	
    	for(int i = 1; i <= m; i++){
    		for(int j = 0; j <= n; j++){
    			dp[i][j] = dp[i - 1][j];//第i间物品有选 or 不选两种状态
    			if(j >= t[i]) dp[i][j] = max(dp[i][j], dp[i - 1][j - t[i]] + w[i]); 
    		}
    	}
    	cout << dp[m][n];*/
    	
    	return 0;
    }
    
    P1616 疯狂的采药

    完全背包问题,滚动数组优化的01背包中时间从小到大枚举即可。

    	for(int i = 0; i < m; i++){
    		cin >> t >> w;
    		for(int j = t; j <= n; j++) dp[j] = max(dp[j], dp[j - t] + w);
    	}
    
    P1802 五倍经验日

    01背包...,每一个好友都有输 or 赢两种状态,dp[j]表示消耗j个药物获得的最大经验

    • j >= use,win or lose : dp[j] = max(dp[j] + lose, dp[j - use] + win);
    • j < use, lose: dp[j] += lose;
    • 存在use == 0的情况
    int n,x,lose,win,use;
    long long dp[10010];
    int main(void){
    	ios::sync_with_stdio(false);
    	cin.tie(0);cout.tie(0);
    	cin >> n >> x;
    	for(int i = 1; i <= n; i++){
    		cin >> lose >> win >> use;
    		for(int j = x; j >= use; j--) dp[j] = max(dp[j] + lose, dp[j - use] + win);
    		for(int j = use - 1; j >= 0; j--) dp[j] += lose;
    	}
    	cout << dp[x] * 5;
    	return 0;
    }
    
    P1002 过河卒
    //A(0,0) --> B(n, m)的路径条数,其中马所控制的八个点不可以走
    //dp[x][y]表示到达x,y点的路径数;
    //由于卒只能向下向右走:dp[x][y] = dp[x - 1][y] + dp[x][y - 1]
    int n,m,hx,hy,dir[4] = {1,-1,2,-2};
    long long dp[25][25];
    bool book[25][25];
    int main(void){
    	ios::sync_with_stdio(false);
    	cin.tie(0);cout.tie(0);
    	cin >> n >> m >> hx >> hy;
    	book[hx][hy] = true;
    	for(int i = 0; i < 4; i++){
    		for(int j = 0; j < 4; j++){
    			if(i == j) continue;
    			if(abs(dir[i]) == abs(dir[j])) continue;
    			int tx = hx + dir[i];
    			int ty = hy + dir[j];
    			book[tx][ty] = true;
    		}
    	}
    	for(int i = 1; i <= n && !book[i][0]; i++) dp[i][0] = 1;
    	for(int i = 1; i <= m && !book[0][i]; i++) dp[0][i] = 1; 
    	for(int i = 1; i <= n; i++){
    		for(int j = 1; j <= m; j++){
    			if(!book[i - 1][j]) dp[i][j] +=dp[i - 1][j];
    			if(!book[i][j - 1]) dp[i][j] += dp[i][j - 1];
    		}
    	}
    	cout << dp[n][m];
    	return 0;
    }
    
    • 滚动数组优化,待填坑...
  • 相关阅读:
    使用 yo 命令行向导给 SAP UI5 应用添加一个新的视图
    SAP Fiori Elements 应用的 manifest.json 文件运行时如何被解析的
    SAP UI5 标准应用的多语言支持
    微软 Excel 365 里如何设置下拉菜单和自动高亮成指定颜色
    SAP Fiori Elements 应用里的 Title 显示的内容是从哪里来的
    本地开发好的 SAP Fiori Elements 应用,如何部署到 ABAP 服务器上?
    如何在 Cypress 测试代码中屏蔽(Suppress)来自应用代码报出的错误消息
    教你一招:让集群慢节点无处可藏
    应用架构步入“无服务器”时代 Serverless技术迎来新发展
    MySQL数据库事务隔离性的实现
  • 原文地址:https://www.cnblogs.com/honey-cat/p/13173419.html
Copyright © 2011-2022 走看看