随笔分类 - 动态规划
摘要:http://acm.timus.ru/problem.aspx?space=1&num=1057其实这题可以算是一个组合数的题目了,主要是将基于其他进制转化为基于2进制的算法,对于某一位不为1的话,那么取其他位的话是一定不满足题意的,所以要找到一个数的最高位大于1,将这一位以及后面的每一位都赋值为1,然后就是一个按位DP的过程了,dp[len][statu]表示长度剩余量为len,要求1的个数为statu个时,并且对后面的位没有要求的情况下,所有可能的解。代码如下:#include <cstring>#include <cstdio>#include <
阅读全文
摘要:这题的状态真的是很难想到,网上的代码都惊人的相似...另一种解法,相比而言好接受一点:#include <cstring>#include <cstdio>#include <cstdlib>#include <algorithm>using namespace std;typedef unsigned long long Int64;Int64 dp[20][3], N;int digit[20];Int64 dfs(int pos, int statu, int limit){ if (pos == -1) { // 如果到了已经枚举了最后一
阅读全文
摘要:这题要注意的就是要构造出两个端点出来,然后直接开辟状态dp[i][j]表示i,j之间的囚犯都救出的最少的金币数,注意此时的边界i,j是不取的。初始条件是dp[i][i+1] = 0.代码如下:#include <cstring>#include <cstdlib>#include <cstdio>#include<iostream>using namespace std;const int inf = 0x3fffffff;int N, P, loc[105], dp[105][105];int dfs(int a, int b){ if(b -
阅读全文
摘要:这里有多个点与原点的连线共线的话,那么需要对其进行并组,将前一个作为单独的一个,把前两个作为单独的一个...最后直接分组背包就可以了。代码如下:#include <cstdlib>#include <cstdio>#include <cstring>#include <algorithm>#define MAXN 205using namespace std;int N, M, cnt[MAXN], vis[MAXN], idx;int f[40005];struct Node{ int x, y, t, v; bool operator <
阅读全文
摘要:首先这题可以用期望DP来计算最后的期望值,由于这题每张卡片对应的概率是不相同的,所以不能像POJ-2096那样dp[i]表示拿到了i 张卡片来表示状态,而是要开一个 1<<N的状态来压缩状态表示拿到不用的卡片的期望值。对于给定的N,我们有dp[(1<<N)-1]=0,因为这已经是最后的状态了。对于dp[i] 我们需要分析其能够到达的状态,如果 N=6, i 的二进制位为 011011,那么可能买零食不改变原来状态,也就是中了已经有了的卡片或者是没有中卡片,所以到达原来状态的概率是p[1]+p[2]+p[4]+p[5]+NONE,这一项是要移到待会儿方程的左边去解的,因为
阅读全文
摘要:这题用贪心是很容易过的,直接先杀死对方单位时间输出较高的对象。这题的动态规划解是将N个敌人压缩到一个int数里面,dp[j] 表示在剩余了j这个数里面所蕴含的敌人的情况下的最大扣血量。dp方程为 dp[s] = min( dp[s - {bit}] + sumdps[s] * h[bit] ) 其中bit枚举每一位。代码如下:#include <cstdlib>#include <cstring>#include <cstdio>#include <algorithm>using namespace std;int dp[1200000], N,
阅读全文
摘要:直接用DP方程直接TLE了,因为数据范围达到了10^9......这题的正解是先用DP方程分别求出在t步走到每一行(列)的可能,再将其相加到一个步数为t的数组中,表示到第t步时,所有行(列)的种数,最后再用一个组合公式,将规定的K步进行分解来求得最后的答案。这题要特别要注意边界条件,还有就是防止溢出。这里用到了一个公式来求组合数 C[i, j] = C[i-1, j] + C[i-1, j-1]。代码如下:#include <cstdlib>#include <cstdio>#include <cstring>#define MOD 1000000007us
阅读全文
摘要:#include <cstdlib>#include <cstring>#include <iostream>using namespace std;int p[1005], w[1005], dp[1005][1005], N, V;void DP(){ memset(dp, 0, sizeof (dp)); for (int i = 1; i <= N; ++i) { for (int j = V; j >= 0; --j) { if (j >= w[i] && dp[i-1][j-w[i]] + p[i] > d
阅读全文
摘要:解决该题的思路就是如何建立状态就保留所有的解(包括临时解)这很简单,该题只是对于某一分钟走或者是休息,而这也只改变其疲劳值,因此开一个二维数组第一维表示该走到了第几分钟,第二维表示疲劳值,保留的值为能够走得最远距离。该题还有一个地方要注意就是疲劳值为零的状态的来源有多个,可以是原来疲劳值为0,1以及能够休息到该分钟为零的任意前面一分钟。f[i][j] 表示第i分钟疲劳值为j能够走得最远距离。f[i][0] = max(f[i-1][0], f[i-k][k]) 其中 1 <= k <= i /2, 因为i-k >= k;f[i][j] (j != 0) = f[i-1][j-
阅读全文
摘要:该题题义很明确,看了题之后也会想到这时一个DP题目,问题在于如何来定义状态,以及建立合理的动态规划方程来求解这个问题。本题的输出是在泡到MM最多的情况下,花最少的时间。因此,时间的权限小于泡到MM的数量,为此我们可以用一个二维背包求解出最多能够泡到多少女生,这个并不难。再往后,如何保证时间是最少的呢,我的做法是再开一个数组,用来记录花费为 i “rmb”,j “rp”的最少时间,将时间数组的更新与二维背包求解最多MM数量做到同时更新,这样便能够保证一定是在泡到MM数量不减少的情况下的最少时间。代码如下:#include <cstdlib>#include <cstring&g
阅读全文
摘要:题义是两个人分别从左上角和右下角互相传递纸条,但是可以将问题转化为同时在左上角向下传递的两个纸条,求这两个不相交的路径的最大权值。TLE了,但总算是把思维的DP弄懂了,总是在路线重复上觉得这个dp方程存在问题,后面才恍悟,在两个纸团坐标相同的点的dp值总是为零的,因为它从头到尾都没有更新。定义的dp方程f[i][j][k][p]是指在1,1这个点同时抛的两个纸团的具体坐标(i,j)和(k,p),方程保证不更新两个点相同的值,方程是这样的:f[i,j,k,p]:=max{f[i-1,j,k-1,p]f[i-1,j,k,p-1]f[i,j-1,k-1,p]f[i,j-1,k,p-1] ...
阅读全文
摘要:代码如下:#include <cstdio>#include <cstdlib>#include <cmath>#include <cstring>#include <iostream>#include <algorithm>#define MAXN 1000005using namespace std;int M, N, seq[MAXN];int pre[MAXN], cur[MAXN];int DP(){ int Max; memset(pre, 0, sizeof (pre)); memset(cur, 0, si
阅读全文
摘要:简单完全背包。代码如下:#include <cstdio>#include <cstdlib>#include <cmath>#include <cstring>#include <iostream>#include <algorithm>#define MAXN 500#define INF 0x3ffffffusing namespace std;int E, F, N, W, dp[10005];struct Node{ int p, w; }e[MAXN+5];void c_bag(int x){ for (int
阅读全文
摘要:代码如下:#include <cstring>#include <cstdlib>#include <cstdio>#include <algorithm>#define MAXN 105using namespace std;int N, M, p[MAXN], v[MAXN], num[MAXN], dp[MAXN];int zo_bag(int v, int p){ for (int i = N; i >= p; --i) { dp[i] = max(dp[i], dp[i-p]+v); }}int c_bag(int x){ int
阅读全文
摘要:题意就不多说了,刚开始还在用搜索来写,定了两个方向,标记去重,各种,然后就TLE了。正解就是枚举行方向的量,再控制列方向的量,使得行和列上的偏移量不超过规定的步数即可,在没有每一次memset的情况下,注意在枚举的时候去掉自己这个点。代码如下:#include <cstring>#include <cstdlib>#include <cstdio>#define MOD 10000#define MAXN 105using namespace std;int G[MAXN][MAXN], n, m;int dp[MAXN][MAXN];inline int
阅读全文
摘要:http://acm.hdu.edu.cn/showproblem.php?pid=1789题义是给定一个作业序列,求如何分配使得得到的分数最多。设 dp[i][j] 代表截止到第i个作业,第j天所能够完成的最多分数。dp方程为:if (1<= j <= e[i].time) dp[i][j] = max(dp[i-1][j], d[i-1][j-1]+e[i].score);if (e[i].time+1 <= j <= Last) dp[i][j] = max(dp[i-1][j], dp[i][j-1]);代码如下:#include <cstdlib>
阅读全文
摘要:题目意思很好懂。暴力的想法是在已知的丑数中选出最小的,保存之,然后乘以2,3,5,7保存起来,这里要注意去重。不得不说其英文输出很坑爹。代码如下:#include <cstring>#include <cstdlib>#include <cstdio>#include <queue>#include <map>#include <iostream>#define MAXN 5850using namespace std;int n, a[4] = {2, 3, 5 ,7};long long ans[MAXN]; prio
阅读全文
摘要:http://acm.hdu.edu.cn/showproblem.php?pid=1421 题义是给定N个物品,从中选取K对,每取一对的花费是两个物品重量之差的平方。求最后采用何种策略才能使得总的花销最少。 该问题的限制条件是取K对以及物品的个数,因此在不优化的情况下,我们使用dp[i][j]来表示在前i见物品中选取j对的最少花费。那么就有动态转移方程: dp[i][j] = min(dp[i-1][j], dp[i-2][j-1]+(w[i]-w[i-1])*(w[i]-w[i-1])); 代码如下:#include <cstdlib>#include <cstring&
阅读全文
摘要:给定一个N*M的01矩阵,在可以交换列的情况下,求出最大的全1的子矩阵。 代码如下:#include <cstring>#include <cstdio>#include <cstdlib>#include <algorithm>#define MAXN 1005using namespace std;int N, M, high[MAXN], temp[MAXN];char G[MAXN][MAXN];int deal(){ int Max = 0; memcpy(temp, high, sizeof (high)); sort(temp+1,
阅读全文
摘要:对于每一个点由其上一步的结点传递过来,存在最优子结构,即对于正确路径的上的任意一点将都是最优的,并且存在最优子结构。保留最优值的时候注意方法,不然TLE。代码如下:#include <cstdio>#include <cstdlib>#include <cmath>#include <cstring>#include <iostream>#define MAXN 200000using namespace std;int N, M, dp[MAXN+5], G[MAXN+5], mm[MAXN+5];inline int max(in
阅读全文


浙公网安备 33010602011771号