dp

畅通工程再续

心不动则不痛 提交于 2020-01-31 04:34:57
不贴题目了 这个题太有意思了!!! 没想到最小生成树的题还能这么搞 竟然一个是托 最后又到最小生成树的经典做法上了 第一次没对 我又仔细看了看题 原来这个也是最小权重啊 我一开始根本没考虑最小的问题 只是把不在一块的岛 连了起来 后来又改了几次 样例都对 我觉得也没啥毛病 但 啊 就是不对 后来我又从CSDN上搜了 那个作者说的让我突然又思路了: 需要往模板方向靠拢,在要求的条件之下,化为: 村1 村2 距离/价钱 不就是把他们两个两个的遍历一遍吗 然后记下他们的编号 和他们之间的距离 就成了经典的最小生成树的问题了 // 这个题太有意思了!!! // 没想到最小生成树的题还能这么搞 // 竟然一个是托 最后又到最小生成树的经典做法上了 // 第一次没对 我又仔细看了看题 原来这个也是最小权重啊 我一开始根本没考虑最小的问题 // 只是把不在一块的岛 连了起来 // 后来又改了几次 样例都对 我觉得也没啥毛病 但 啊 就是不对 // 后来我又从CSDN上搜了 // 那个作者说的让我突然又思路了: // 需要往模板方向靠拢,在要求的条件之下,化为: 村1 村2 距离/价钱 // 不就是把他们两个两个的遍历一遍吗 然后记下他们的编号 和他们之间的距离 // 就成了经典的最小生成树的问题了 # include <iostream> # include <vector> # include

最大连续子序列

与世无争的帅哥 提交于 2020-01-31 04:26:27
# include <stdio.h> # include <malloc.h> # include <string.h> # include <string.h> # include <iostream> using namespace std ; int MaxSumSub_1 ( int a [ ] , int n ) { //暴力法:算法复杂度为 n^3 int max = 0 ; for ( int i = 0 ; i < n ; ++ i ) { for ( int j = i ; j < n ; ++ j ) { int sum = 0 ; for ( int k = i ; k <= j ; ++ k ) { sum + = a [ k ] ; } if ( max < sum ) max = sum ; } } return max ; } int MaxSumSub_2 ( int a [ ] , int n ) { //暴力法的优化:算法复杂度 n^2 int max = 0 ; for ( int i = 0 ; i < n ; ++ i ) { int sum = 0 ; for ( int j = i ; j < n ; ++ j ) { sum + = a [ j ] ; if ( max < sum ) max = sum ; } } return

(树形dp,树的直径)HDU4607Park Visit

落花浮王杯 提交于 2020-01-23 03:03:27
HDU4607 Park Visit 题意&思路: 公园有n个景点,有n-1条路将他们相连,问游览k个经典最少需要走的路径。 树的直径的模板题。 树的直径就是两个结点路径最长的一条。我们可以用搜索(DFS/BFS)两次来求,也可以用树形dp。 用dp[0][u]表示u结点到其他结点路径的最大值,dp[1][u]表示u结点到其他结点路径的次大值。 令v为u的子节点,w为u和v的权值。如果dp[0][u]<dp[0][v]+w[u][v],则dp[1][u]=dp[0][u];dp[0][u]=dp[0][v]+w[u][v]。如果dp[1][u]<dp[0][v]+w[u][v],则dp[1][u]=dp[0][u]+w[u][v]。 mx为最长的一条路径,mx=max(mx,dp[0][i]+dp[1][i])。游览k个景点,如果k<=mx+1,则只需要走k-1条路;如果k>mx+1,就需要走回头路,所以答案是mx+2*(mx-k-1)。 代码: # include <bits/stdc++.h> const int N = 1e5 + 10 ; const int mod = 1e7 + 9 ; const int maxn = 0x3f3f3f3f ; const int minn = 0xc0c0c0c0 ; const int inf = 99999999 ; using

I love you-dp子序列个数统计

我与影子孤独终老i 提交于 2020-01-22 04:46:48
传送门:I love you 题意:给出一个文本串,求包含子序列(可以不连续)"iloveyou"的个数 dp[i][j]表示子串0—i-1,文本0—j的情况下文本串中有子序列的个数。 先考虑s再考虑t 状态转移方程: 当s[i-1] !=t[j-1]时,dp[i][j]=dp[i-1][j];当前0—i-1与0—j-1和0—i-2与0—j-1的一样 当s[i-1]==t[j-1]时,dp[i][j]=dp[i-1][j-1]+dp[i-1][j];当前情况产生了新的可能,这些可能由dp[i-1][j-1]延续,以及加上dp[i-1][j]。 # include <bits/stdc++.h> using namespace std ; const int mod = 20010905 ; string S , T ; int dp [ 1084594 ] [ 10 ] ; int solve ( ) { int ss = S . size ( ) + 1 ; int st = T . size ( ) + 1 ; dp [ 0 ] [ 0 ] = 1 ; for ( int i = 1 ; i < ss ; ++ i ) { dp [ i ] [ 0 ] = 1 ; } for ( int i = 1 ; i < ss ; ++ i ) { for ( int j = 1 ; j

经典数塔问题(动态规划)

妖精的绣舞 提交于 2020-01-20 16:18:38
有形如下图所示的数塔,从顶部出发,在每一结点可以选择向左走或是向右走,一直走到底层,要求找出一条路径,使路径上的值最大。 从顶点出发时到底是向左走还是向右走应取决于向左走能取得最大值还是向右走能取得最大值,只有两条路径上的最大值求出来了才能做出决策, 即dp[1][1] = max(dp[2][1],dp[2][2]) 故由此推得状态转移方程为dp[i] = max(dp[i+1][j],dp[i+1][j+1]); 边界条件即最下边一层的数据 //数塔问题 #include<iostream> using namespace std; int main() { int n; int f[100][100] = {0}; int dp[100][100] = {0};//状态数组 while(cin>>n) { memset(f,0,sizeof(f)); memset(dp,0,sizeof(dp)); //输入数塔 for(int i=1;i<=n;i++) for(int j=1;j<=i;j++) cin>>f[i][j]; //边界,最底下一层的数塔dp值等于f值 for(int j=1;j<=n;j++) dp[n][j] = f[n][j]; for(int i=n-1;i>=1;i--) { for(int j=1;j<=i;j++) { //状态转移方程 dp[i

Codeforces 1149 B - Three Religions

▼魔方 西西 提交于 2020-01-19 11:31:55
B - Three Religions 思路:dp dp[i][j][k]:a的前i个和b的前j个和c的前k个能构成的最前面的位置 删字符时状态不用改变,加字符时只会改变1*250*250个状态 代码: #pragma GCC optimize(2) #pragma GCC optimize(3) #pragma GCC optimize(4) #include<bits/stdc++.h> using namespace std; #define y1 y11 #define fi first #define se second #define pi acos(-1.0) #define LL long long #define ls rt<<1, l, m #define rs rt<<1|1, m+1, r //#define mp make_pair #define pb push_back #define ULL unsigned LL #define pll pair<LL, LL> #define pli pair<LL, int> #define pii pair<int, int> #define piii pair<pii, int> #define pdi pair<double, int> #define pdd pair<double, double>

2016 Multi-University Training Contest 2 solutions BY zimpha

廉价感情. 提交于 2020-01-19 10:40:16
Acperience 展开式子, \(\left\| W-\alpha B \right\|^2=\displaystyle\alpha^2\sum_{i=1}^{n}b_i^2-2\alpha\sum_{i=1}^n{w_ib_i}+\sum_{i=1}^{n}w_i^2\) . 由于 \(b_i\in \{+1,-1\}\) , 那么 \(\displaystyle\sum_{i=1}^{n}b_i^2=n\) , 显然 \(c=\displaystyle\sum_{i=1}^{n}w_i^2\) 也是常数. 转化成求 \(\displaystyle\alpha^2n-2\alpha\sum_{i=1}^n{w_ib_i}+c\) 的最小值. 对于固定的 \(\alpha>0\) , 只要 \(\displaystyle\sum_{i=1}^n{w_ib_i}\) 最大就好了. 显然 \(b_i=sign(w_i)\) 的时候, \(\displaystyle\sum_{i=1}^n{w_ib_i}=\sum_{i=1}^{n}|w_i|\) 最大. 进一步的, 上面显然是一个关于 \(\alpha\) 的二次方程, 于是当 \(\alpha=\frac{1}{n}\displaystyle\sum_{i=1}^n{w_ib_i}=\frac{1}{n}

货币找零

泪湿孤枕 提交于 2020-01-19 00:28:45
class Solution(object): def coinChange(self, coins, amount): """ :type coins: List[int] :type amount: int :rtype: int """ n = len(coins) # dp[i]表示amount=i需要的最少coin数 dp = [float("inf")] * (amount+1) dp[0] = 0 for i in range(amount+1): for j in range(n): # 只有当硬币面额不大于要求面额数时,才能取该硬币 if coins[j] <= i: dp[i] = min(dp[i], dp[i-coins[j]]+1) # 硬币数不会超过要求总面额数,如果超过,说明没有方案可凑到目标值 return dp[amount] if dp[amount] <= amount else -1 来源: CSDN 作者: ailinyingai 链接: https://blog.csdn.net/ailinyingai/article/details/104030940

[LeetCode] 1025、除数博弈

*爱你&永不变心* 提交于 2020-01-18 09:35:22
题目描述 爱丽丝和鲍勃一起玩游戏,他们轮流行动。爱丽丝先手开局。最初,黑板上有一个数字 N 。在每个玩家的回合,玩家需要执行以下操作: 选出任一 x ,满足 0 < x < N 且 N % x == 0 。 用 N - x 替换黑板上的数字 N 。 如果玩家无法执行这些操作,就会输掉游戏。只有在爱丽丝在游戏中取得胜利时才返回 True ,否则返回 false 。假设两个玩家都以最佳状态参与游戏。 解题思路 博弈问题,两种解题思路: 归纳法 :神仙解法,记一下这个解法即可。 首先明确: 最终结果应该是占到 2 的赢,占到 1 的输 ; 若当前为奇数,奇数的约数只能是奇数或者 1,因此下一个一定是偶数; 若当前为偶数, 偶数的约数可以是奇数可以是偶数也可以是 1,因此直接减 1,则下一个是奇数; 因此, 偶则赢 (爱丽丝只需一直选1,使鲍勃一直面临N为奇数的情况,这样爱丽丝稳赢), 奇则输 (爱丽丝第一次选完之后N必为偶数,那么鲍勃只需一直选1就会稳赢)。 动态规划 :正常思路 设 dp[n] 表示:当黑板上的数字为 n 时,此时正在玩游戏的人的输赢情况。(必输或者必赢,因为题目中说了“两个玩家都以最佳状态参与游戏”) 如果在Alice取了数字 x ,,那么显然 dp[n] 与 dp[n-x] 输赢情况相反。 x 可以取的值很多,只要 dp[n-x_i] 中任意一个为 False ,

LeetCode(62):不同路径

↘锁芯ラ 提交于 2020-01-18 05:23:11
Medium! 题目描述: 一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。 问总共有多少条不同的路径? 例如,上图是一个7 x 3 的网格。有多少可能的路径? 说明: m 和 n 的值均不超过 100。 示例 1: 输入: m = 3, n = 2 输出: 3 解释: 从左上角开始,总共有 3 条路径可以到达右下角。 1. 向右 -> 向右 -> 向下 2. 向右 -> 向下 -> 向右 3. 向下 -> 向右 -> 向右 示例 2: 输入: m = 7, n = 3 输出: 28 解题思路: 这道题是每次可以向下走或者向右走,求到达最右下角的所有不同走法的个数。我们需要用动态规划Dynamic Programming来解,我们可以维护一个二维数组dp,其中dp[i][j]表示到当前位置不同的走法的个数,然后可以得到递推式为: dp[i][j] = dp[i - 1][j] + dp[i][j - 1],这里为了节省空间,我们使用一维数组dp,一行一行的刷新也可以。 C++解法一: 1 // DP 2 class Solution { 3 public: 4 int uniquePaths(int m, int n) { 5 vector