随笔分类 -  动态规划

摘要:题意:不想说了。。。我们只需要关心被选择的点,先预处理出来每两点间的最短路,然后问题就变成找到一条从1出发最后回到1且经过所有被选择点的最长路径,赤裸裸的TSP问题,状态压缩可破之。最初写了个spfa,但是效率无比低,其实对于这种特殊的状态转移(只能小的向大的转移),可以直接递推。 1 #include 2 #include 3 #include 4 #include 5 #include 6 #include 7 #include 8 #include 9 #include10 #include11 #include12 #include13 #include14 using namespa 阅读全文
posted @ 2013-08-28 19:44 silver__bullet 阅读(216) 评论(0) 推荐(0)
摘要:题意: 先定义一个数的power value,把这个数看成一个字符串,他的最长上升子序列的长度就是他的power value,求某个区间内power value等于k的数的个数。解法: 很显然要数位DP,先考虑LIS的nlogn解法,我们用dp[len]记录LIS长度为len时的最后一个数的大小,然后不断更新这些值,让每一个值都尽可能小,比如我现在的LIS是1 2 4 6,这时候下一个数是3,那么我们就要更新成1 2 3 6,让前面的数尽可能的小,这样就是为了能让后面的数有更多的机会被加入。 同理,因为数字只有10个,我们可以状态压缩,记录每个数字是否出现在当前的LIS中,然后根据这个状... 阅读全文
posted @ 2013-08-15 11:01 silver__bullet 阅读(2028) 评论(0) 推荐(0)
摘要:解法: 状态压缩,首先注意到第三种可以用两个第五种的块代替,所以枚举状态的时候不用考虑3. dp[i][mask]记录第 i行状态为mask时能覆盖的最大面积,状态转移的时候直接枚举除了铺第一种砖块之外的所有状态,最后作下减法即可求出需要几个第一种砖块。 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<bitset> 5 #include<iostream> 6 #define N 1010 7 using namespace std; 8 阅读全文
posted @ 2013-03-15 19:48 silver__bullet 阅读(210) 评论(0) 推荐(0)
摘要:题意:统计某段区间内满足它所有非零数位能整除这个数本身的数的个数。解法; 自己搞的时候除了想到开N维数组分别记录之外没什么别的想法>< 2~9所有数的lcm最大是2520,dp[pos][pre_mod][pre_lcm]记录前pos位数对2520取余为pre_mod并且非零位的lcm位pre_lcm的个数。 因为2到9的lcm最多只有不到50个,我们需要对lcm离散化一下。。。。 1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm 阅读全文
posted @ 2013-03-11 20:29 silver__bullet 阅读(1166) 评论(0) 推荐(0)
摘要:解法: 不含前导0,那么最开始dfs的时候可以把最高位之前那位设为11,这样的话最高位的数选取不受限制,还要注意的就是枚举到当前位的时候数是不是已经大于0。 1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 #define N 20 6 using namespace std; 7 typedef long long ll; 8 ll dp[N][N]; 9 int bit[N];10 ll dfs(int pos,int st, 阅读全文
posted @ 2013-03-09 14:49 silver__bullet 阅读(621) 评论(0) 推荐(0)
摘要:解法: 数据范围很小,其实直接暴力就行,但是刚开始学数位dp,所以还是dp了一下,学习了一下数位dp的dfs写法,感觉简洁明了,但是要注意细节。 dp[i][0]:前i位不含不吉利数的个数。 dp[i][1]:前i位不含不吉利数且i+1位是6的个数。 dp[i][2]:前i位含不吉利数的个数。 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define N 10 5 using namespace std; 6 int bit[N]; 7 int dp[N][3]; 8 9 i 阅读全文
posted @ 2013-03-09 14:44 silver__bullet 阅读(2302) 评论(0) 推荐(1)
摘要:题意:给定n(n<=16&&n为偶数)对点的坐标,现在要将他们分成n组,使得每组两个点距离之和加起来最小。。。解法: 状态压缩,用0 1表示该点是否已经被分配完。。然后记忆化搜索。。。 1 #include<cstdio> 2 #include<cstring> 3 #include<string> 4 #include<iostream> 5 #include<cmath> 6 #include<algorithm> 7 #define N 1<<21 8 #define M 30 9 阅读全文
posted @ 2012-12-27 18:30 silver__bullet 阅读(233) 评论(0) 推荐(0)
摘要:解法:状态压缩。只有12个洞,所以状态最多只有2^12种。。。然后dfs一下找出来所有合法状态即可。 对于位运算的操作: x&(1<<i)表示取出第i位; x&(~(1<<i))表示把第i位变成0; x|(1<<i)表示把第i位变成1; 1 #include<cstdio> 2 #include<iostream> 3 #include<string> 4 #include<cstring> 5 #include<algorithm> 6 #include<queue> 阅读全文
posted @ 2012-12-26 18:12 silver__bullet 阅读(220) 评论(0) 推荐(0)
摘要:题意:给定n个物品,用这n个物品填充一个背包,使得没有被装入的物品一定塞不进背包,统计方案数。解法:对于普通的01背包统计方案数很简单,dp[j]=dp[j]+dp[j-w[i]]...这题需要对重量进行排序,然后枚举每个物品,使之成为没有被装入背包的最小重量,那么对于重量小于w[i],的,一定会被装入背包,对于大于w[i]的,我们只需要进行一次01背包统计方案即可,最后找出满足条件的累加。。。 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define N 1010 5 #d 阅读全文
posted @ 2012-12-06 23:27 silver__bullet 阅读(160) 评论(0) 推荐(0)
摘要:题意:从给定的序列中选出一定数目的三元组x,y,z(x<=y<=z),使得所有三元组中(x-y)^2之和最小解法:解法类似于hdu搬寝室那个题,但是这里多了一个z的限制,对于z的处理,我们可以把这个序列按照降序排列,这样的话就能消除z的影响. 为什么呢?想一下状态转移方程,dp[i][j]=min(dp[i-1][j],dp[i-2][j-1]+(s[i]-s[i-1])*(s[i]-s[i-1])); 也就是说dp[i][j]的值可能在求dp[i-1][j]时已经得到了,而在这里,我们可以通过"j<=i/3"这个限制保证不会选到最大的... 1 #inc 阅读全文
posted @ 2012-11-30 21:21 silver__bullet 阅读(217) 评论(0) 推荐(0)
摘要:题意:给定一个树形图,现在选择其中一个节点,为了从此节点到达所有的其他节点需要改变一些边的方向,求出最小需要修改的边数以及满足最优解的节点。。解法:树形dp,第一次随意指定一个点为根,然后根据子节点的信息更新父节点,dp[i][0]表示使得i节点能到达它所有子节点需要修改的边数。 第二次dp,根据第一次dp的结果,利用父节点的信息来更新子节点,dp[i][2]表示使得i节点到达其他所有节点需要修改的边数。 如果pre[i]指向i,那么dp[i][1]=dp[pre[i]][0]-1; 如果i指向pre[i],那么dp[i][1]=dp[pre[i]][0]+1; 1 #include<i 阅读全文
posted @ 2012-11-06 17:32 silver__bullet 阅读(590) 评论(0) 推荐(1)
摘要:题意:一辆车从起点走到终点,途中有些加油站,给出每个加油站距离和油价,最后求从起点到终点最小费用,其中在起点有100升油,要求到终点至少也还有100升油。解法:dp[i][j]记录走到第i站升j升油的最小费用,用当前的合法状态去更新后一个状态。 需要注意的是最后一站不一定在终点,注意读入方式。。。。 1 #include<iostream> 2 #include<cstring> 3 #include<algorithm> 4 #include<cstdio> 5 #define N 110 6 #define M 210 7 using nam 阅读全文
posted @ 2012-11-05 12:04 silver__bullet 阅读(274) 评论(0) 推荐(0)
摘要:题意:给定n个物品,每个物品有两个价值,x,y,问能否从中选择一些物品(数量任意),使得sum(x)^2+sum(y)^2==s*s分析:二维费用的背包,dp[i][j]表示凑出两种费用分别为i,j的最小硬币数 1 #include<iostream> 2 #include<cstring> 3 #include<algorithm> 4 #define N 500 5 using namespace std; 6 const int inf=(1<<30); 7 int dp[N][N]; 8 int w1[N],w2[N]; 9 int ma 阅读全文
posted @ 2012-11-02 19:58 silver__bullet 阅读(160) 评论(0) 推荐(0)
摘要:题意:给定一棵树,求切出有n个结点的子树至少要切几条边。解法:dp[i][j]记录使得以i为根的子树有j个结点最少要切几条边 dp[i][j]=min(dp[i][j],dp[i][j-k]+dp[son[i]][k]) 最后统计答案时要注意,如果不是根节点还要+1...切掉这个节点与其父亲之间的边 1 #include<iostream> 2 #include<vector> 3 #include<cstring> 4 #include<algorithm> 5 #define N 200 6 using namespace std; 7 co 阅读全文
posted @ 2012-10-31 19:48 silver__bullet 阅读(199) 评论(0) 推荐(0)
摘要:题目描述:...解法: 树形dp+分组背包。 dp[i][j]记录以i为根的子树分配j个用户时的最大收益,cnt[i]记录以i为根的子树有几个叶子节点,对于每个i,背包容量即为cnt[i]的大小。 将i的每个子节点看作一组,这组背包的物品重量即为1~cnt[son[i]],由于只能从每组中选出一种物品,所以可以看做分组背包。 1 #include<iostream> 2 #include<cstring> 3 #include<algorithm> 4 #include<vector> 5 #define N 3010 6 using names 阅读全文
posted @ 2012-10-29 21:31 silver__bullet 阅读(169) 评论(0) 推荐(0)
摘要:题目描述: 给定n个物品及m钱,对于每个物品有三个属性,价格p,价值v,q,如果手中的钱不足q,即使能够买得起这个物品,也不能交易,求最后能买到的物品最大价值。分析: 带限制的01背包。最容易想到的就是要按某种方式进行排序,可以先想两个问题。 1.为什么普通的01背包可以不用排序? 因为在普通的01背包问题当中每个物品是相对独立的,也就是说取得全局最优解与物品的放入顺序无关,所以不必排序就可以直接进行dp,而在这个问题中却并非如此,由于q的存在,当某一物品放入后可能就会对后面的物品造成影响,举个例子,比如背包容量为8,有两个物品,p1=5,q1=6,v1=1,p2=2,q2=4... 阅读全文
posted @ 2012-10-24 13:39 silver__bullet 阅读(296) 评论(1) 推荐(1)
摘要:分析:因为要洗完所有同种颜色的才能洗下一种颜色,所以先按颜色排序,对每种颜色做一次01背包。取两个最少时间的最大值,累加 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<map> 5 #include<string> 6 #include<iostream> 7 #define N 1100 8 using namespace std; 9 int dp[N][N],w[N][N],cnt[N],sum[N];10 int ma 阅读全文
posted @ 2012-10-22 21:10 silver__bullet 阅读(162) 评论(0) 推荐(0)
摘要:01背包统计第k优解,多开一维的数组,用来记录第几优解,然后每次更新的时候合并一下。。。 1 #include<iostream> 2 #include<cstring> 3 #include<algorithm> 4 #define N 1100 5 #define K 100 6 using namespace std; 7 int dp[N][K],w[N],v[N],s[N]; 8 bool cmp(int a,int b){ 9 return a>b;10 }11 int main(){12 int n,m,k,T;13 cin>> 阅读全文
posted @ 2012-10-22 13:02 silver__bullet 阅读(169) 评论(0) 推荐(0)
摘要:题目描述:...分析:因为不同年份之间没有什么互相影响,所以可用完全背包求解,唯一不同的就是每年的背包容量都在变大。 另外由于物品价钱都是1000的倍数,所以可以同时除以1000,减少内存。 1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 #define N 100010 6 using namespace std; 7 int dp[N],w[N],v[N]; 8 int main(){ 9 int t;10 cin>& 阅读全文
posted @ 2012-10-20 22:00 silver__bullet 阅读(119) 评论(0) 推荐(0)
摘要:题目描述; 给定几种钱的面值,问用这些钱凑出n的价值有多少中方案。分析:背包问题,统计填满背包的方案数。 dp [ i ] [ j ]表示用前j种面值凑出i钱的方案数。 dp [ i ] [ j ]=sum { dp [ i - k*s [ j ] ] [ j-1 ] } 1 #include<iostream> 2 #include<cstring> 3 #include<algorithm> 4 #define N 7500 5 using namespace std; 6 typedef long long ll; 7 ll dp[N][5]; 8 i 阅读全文
posted @ 2012-10-20 21:44 silver__bullet 阅读(180) 评论(0) 推荐(0)