随笔分类 - 动态规划
摘要:LICS的应用。还是从最后的结果考虑,肯定是在某个位置的i左边(包括i)递增的序列,右边(包括i)相应的对称的递减的序列,这个序列肯定是,1--i和i--n的逆序的公共递增序列,而1--i和i--n的逆序的公共递增序列肯定是一个符合题意的选择,那么以i为分界点的最优解肯定就是1--i和i--n的逆序的最长公递增序列。然后枚举位置i取以i为分界点的最优解的最大解就可以了。先按这个思路A了,有很多无用的循环,又优化了下。 1 #include 2 #include 3 #include 4 #include 5 #include 6 #include 7 #include 8 #in...
阅读全文
摘要:看了http://wenku.baidu.com/view/3e78f223aaea998fcc220ea0.html 1 #include 2 #include 3 #include 4 #include 5 #include 6 #include 7 #include 8 #include 9 #define LL long long10 using namespace std;11 const int inf=0x3f3f3f3f;12 const int maxn=500+10;13 int a[maxn],b[maxn],f[maxn]; 14 int main...
阅读全文
摘要:DP+简单优化,状态转移方程容易看出,优化看了http://hi.baidu.com/forverlin1204/blog/item/df9c62dc0fb16bd38d1029d8.html。哎,太粗心了,初始化时忘了得平方,看了1个多小时才发现 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 const int inf=2000000000; 6 const int maxn=100000+10; 7 int f[100+10]
阅读全文
摘要:状态转移方程还是很容易想出的,但是n的限值1000不知道为什么 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 const int maxn=100+10; 6 double f[2][maxn]; 7 int c; 8 int n,m; 9 int main()10 {11 while(scanf("%d",&c)&&c)12 {13 scanf("%d%d",&am
阅读全文
摘要:状态压缩DP基础题 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 const int maxn=15; 6 const int mod=100000000; 7 int num[maxn],s[200]; 8 int f[maxn][200],amoun[1<<13]; 9 int main()10 {11 //freopen("1.txt","r",stdin);12 int
阅读全文
摘要:DP解之,边界纠结了两个小时,不过还好一次AC,f[i][j]表示已节点已为根的有j个节点所需去掉的边,这个过程可由分组背包的思想来完成,确定最优解每个子树应该有的节点数。最后就是比较i(i为每个节点的编号)为根的保留p个节点的最小值,p为要保留的节点数。 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 const int maxn=150+10; 6 const int inf=0x3f3f3f3f; 7 int f[maxn][
阅读全文
摘要:树形DP,f[j][i]表示有j个robot遍历i及其子树并且在此子树返回地球所需的最小值,但还有k个robot遍历子树i及其子树,再返回父亲节点m个机器人这种情况,但是可以证明这种情况一定不会是最优解,所以不予考虑。还有一个地方就是f[0][i]表示用0个robot遍历意思就是说用n个机器人遍历此子树,再返回,可知n=1,道理和前面那种情况的道理一样。在求f[i][j]是用的是分组背包的思想,刚开始多用了一个数组g[][],来实现这个过程,后来看了其他人的代码,想了一想,可以用滚动数组优化,用f[i][j]就可以实现这个过程了#include <iostream>
#includ
阅读全文
摘要:状态压缩DP,f[j][i]表示前i行棋子放置状态状态为j的方法数就0<=j<=1<<n,比如j=01010000,表示前i行第5列和第7列放置了棋子的方法总数,具体的递推过程代码如下#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int n,k;
int num[10],f[1<<8][10],vis[10][10],pa[1<<8];
int main()
{ while(~scanf("%
阅读全文
摘要:数位DP。假设长度为s的数字,如果是题目中要求的数字时,肯定是每个位置i ,j,1--i非递减,j--s非递增,然后枚举每个点把左右两方相乘,但是想了想,这么简单的统计会造成很多重复,然后再分析,对于i,j无非三种情况i所在位置数字a>j所在位置数字b,a==b,a<b,先算1--s中的每个位置第一种情况的个数的和,然后发现a==b,a<b的所有情况都可化为第一种情况,所以就不用再求这两种情况的数目,因为第一种情况的所有满足题意的数字已经包括了后两种情况满足意一的数字,所以定义状态f[i][j]表示以数字j结尾的长度为i的非递减数字的个数,还有自己感觉数位DP最坑的地方就是细
阅读全文
摘要:数位DP,各种理解难题#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#define LL long long
using namespace std;
unsigned long long n;
LL f1[25],f2[25],f3[25];
int s[25];
int t;
int main()
{ cin>>t; int i,j,k; f1[0]=0;f2[0]=1;f3[0]=0; for(i=1;i<=19;i++)
阅读全文
摘要:单调队列优化DP//状态转移方程:f[i][j]=min(f[i-k][j-1]+(s[i]-s[i-p])*g[j])
#include <iostream>
#include <cstdio>
#include <cstring>
#define LL long long
using namespace std;
const LL inf=0x3f3f3f3f3f3f3f3f;
LL x[10000+10],s[10000+10],q[10000+10];
LL g[200+10];
LL f[2][10000+10];
int n,k,a,b;
int
阅读全文
摘要:还是思维不够灵活,刚开始,只想到了那个O(n3)的算法,知道肯定不行,苦苦思索,实在想不出来,浏览了一下其他人的博客,刚扫一眼,突然想到了还是从最优解的最后的状态考虑,得到了O(n2)的算法,就是对于节点i,枚举,在他左边的与他举例小于l3的点,得到状态转移方程f[i]=min(f[j]+cost),ac之,然后看了浩神的博客,还可以用二分优化,想了想,确实可以,因为点到s起点的举例是单调非减的,对于同一段的肯定最左边的最优,二分得之#include <iostream>
#include <cstdio>
#define LL __int64
#define min(
阅读全文
摘要:dp+线段树,dp是核心,线段树用来优化复杂度,dp过程好像,但是要确定从一个fence边缘向下沿直线走,下一个fence是哪个,最朴素的想法就是从上到下扫描,时间为O(n2),数据量比较大,可能会超时。然后用线段树来优化这个过程,当输入第i个fence的左右点时,1~i-1的fence所覆盖区间已插入到了线段树中(并在所覆盖的区间发记录fence编号)那么此时,求fence(i)的左点l向下会走到哪个fence,可以从线段树的根开始搜索,搜索到l的这条路径上的最大编号,也就是覆盖了点l的区间上的最大编号,从而得到所求编号#include <iostream>
#include &
阅读全文
摘要:树形DP,f(i,j)表示i节点及其子树得到j个国家所需的最小贿赂,对于j==i子树的节点总数sum,所需的最小费用肯定就是i节点本身的cost,对于j<sum的情况,肯定只有在其子树中选,如果选了i就是把整个子树都选了,然后,这个过程用的是01背包的思想,不知道这个词用的 恰不恰当,但想清楚,这个DP过程就可以了,对每个i的子树,恩。//思路来啦
#include <iostream>
#include <cstdio>
#include <cstring>
#define mem(a,b) memset(a,b,sizeof(a))
#define
阅读全文
摘要:状态压缩,看了周伟的动态规划之状态压缩,讲解的很详细,从写程序,到ac花了7个小时,3个小时敲代码,并理思路,4个小时调错,最后发现还是粗心问题,算法上病没有错误,不能在等啦,以后wa后,先仔细把代码看一遍,要有耐心呢,不能过度依赖调试,可能后者会浪费更多的时间#include <iostream>
#include <cstdio>
#include <string.h>
#define max(a,b) ((a)>(b)?(a):(b))
using namespace std;
char g[100+10][10+10];
int c[65];
阅读全文
摘要:从最优解的结果考虑,f(s)表示节点集合s最多可分为多少组,如果s中节点及其所连节点的并集是节点的全集的话说明s至少可分为一组,反之,可知f(s)=0,当确定s至少可分一组时,可知其最优解的组成肯定是s的某一子集s0(s0中各节点及其联接的节点的并集为全集且s0只能分成一组否则会造成浪费)+(s-s0),那么f(s)=max{f(s-s0)+1.#include <iostream>
#include <cstdio>
using namespace std;
const int maxn=20;
int n;
int p[maxn];
int f[1<<m
阅读全文
摘要:完全背包问题的变形,79ms,不过此题需要一个优化,就是把背包实际容量除以1000,不优化的话,数据量很大,会超时。刚开始优化直接定义成double,除了之后再乘,wa,因为有浮点误差,后来考虑了一下,改为了int,ac#include <iostream>
#include <cstdio>
using namespace std;
int amount;
int d,year;
int intere[11];
int v[11];
int f[100000];
int main()
{ int N; cin>>N; while(N--) { cin>
阅读全文
摘要:又是LIS,又没看出来,写了一个O(n2),用滚动数组优化的算法,超时,瞥了一眼discuss看到了LIS这个字眼,一想,还果然可转化为LIS,而且还这么明显,居然没看出来#include <iostream>#include <cstdio>#include <algorithm>using namespace std;const int maxn=40000+10;const int inf=200000000;int num[maxn];int f[maxn],d[maxn];int main(){ int n,p; scanf("%d&qu
阅读全文
摘要:dp状态转移方程:d(i,j)=sum(i,j)-min{d(i+1,j),d(i+2,j)...d(j,j),d(i,j-1),d(i,j-2)...d(i,i),0}可化为d(i,j)=sum(i,j)-min{f(i+1,j),g(i,j-1),0}#include <iostream>#include <cstring>#include <cstdio>using namespace std;const int maxn=100+10;int arr[maxn];int f[maxn][maxn],d[maxn][maxn],s[maxn],g[ma
阅读全文
摘要:递推,把问题转化为具有相同问题的子问题,通过子问题最后所剩余的编号,退出此问题所剩余的编号#include <iostream>
using namespace std;
const int maxn=10000+10;
int f[maxn];
int main()
{ int n,k,m; while(~scanf("%d %d %d",&n,&k,&m)) { if(!n&&!k&&!m) break; f[1]=0; for(int i=2;i<=(n-1);i++) f[i]=(f[i-1]
阅读全文

浙公网安备 33010602011771号