poj1837:大意,给定天平的位置和砝码,找到所放的位置能够使天平平衡。求有多少种摆放的方式。为了表明摆每个天平时的状态,可用一个度来表示,0表示平衡,<0表示左边重,>0表示右边重。因为数据范围为-7500,7500,所以可以用7500来表示平衡。
poj1260:用dp[i]来表示处理第i个珍珠,因为对于第i个品质的珍珠,要么自己买,要么前面的珍珠和他一起湊过来买。所以状态转移方程为:dp[i] = min{dp[j] + (sums[i] - sums[j] + 10) * price[i]};其中(0<j<i),二重循环解决问题。
poj1018:首先会定义一个状态dp[i]来表示处理第i件物品,然而第i件物品的转移要依据前面的物理,会违背无后效性的原则,所以还需要增加定义一个状态来表示处理第i件物品时前i - 1件物品的最小带宽。
那么dp[i][j]应该代表什么呢?一开始已经想到了前面二维状态的代表,而没有想到dp[i][j]应该代表什么。而应该的想法是既然最小带宽已经被表示了,为了求到最大的B / P的话,B是已经知道的。所以我们
应该使dp[i][j]代表处理第I件物品,最小带宽为j的最小总价格,因为最小带宽只能够从输入设备那里面得到,所以还需要用dp[i][j] = -1来表示没有该最小带宽。那么状态方程就可以表示成dp[i][j] = min(dp[i - 1][k] + price[k]) (其中dp[i - 1][k]因该首先
是可以达到的,然后可以达到之后,进行状态的转移,可以转到dp[i][k],如果第m件产品的带宽比该最小带宽大,或者是转移到dp[i][min],表示第m件产品的带宽比最小带宽小)。最后枚举所有可能的最小带宽,求
其中的最大值。
poj1050:最大矩阵和,直接枚举,从i到j行,假设是最大矩阵和所在的行数,那么问题就划分成为了最大数组和,直接采用O(n)的算法求得最大数组和,即可输出答案。
poj1083:记录区间重叠数,可以采用一个vis数组,从vis[start]记录到vis[end],每次vis[k]++即可,然后找出最大的重叠数,找出来之后则是最大的不能并行移动的桌子数目,则最后乘以10输出答案。
poj1125:Floyd算法,计算次序很重要,k最先被计算,然后依次是I和J.如果存在d[i][j] = INF的话,表明i到j之间不存在联通的路
poj1178:Floyd算法,题意是有很多个骑士,然后有一个国王,他们现在都要移动要某一个方格里面,如果一个骑士在中途碰见国王的话,可以带着国王一起走,相当于国家不要再移动了。
没有思路怎么去做。1:不知道在哪个点汇合,2:不知道在哪个点骑士会碰见国王。3:不知道是哪个骑士会被碰见国王。如果有很多未知情况的话,第一要看数据范围,看能不能进行枚举。
如果可以采取枚举的话,就去枚举。而本题的数据范围为64 * 64 * 64,明显可以采用枚举的方法。进行一次预处理。如果知道了哪个点汇合,哪个点骑士碰见国王,哪个骑士碰见国王的话,则骑士应该
采取最小步骤跳到国王那,国王应该采取最小步骤跳到中间步骤那,骑士应该采取最小步骤跳到终点,所以是一个最短路径的算法。而利用了枚举,所以很明显的要采取Floyd算法来计算任意两点之间的
路径。
poj1189:求选去一些钉子之后道尔顿板落到第I个格子的概率,如果第n层的i个格子摘去的话,则从它经过的球直接下落。采取模拟球下落的方法,设number[i][j]为第i层第j个空洞的球数,那么如果
它下面的钉子被摘去的话,number[i][j]个球就直接会落到number[i + 2][j + 1],否则的话number[i][j]就会分散到number[i + 1][j]和number[i + 1][j + 1],最后算出第number[n][m]的球数,除以2^n即可。
因为要输出既约整数,分别除以两个的最大公约数,直接输出。
poj1322:有N种颜色的巧克力,从一个包里面依次拿M次,然后每遇到两个相同颜色的巧克力就吃掉,问最后剩K个巧克力的概率是多大。
没有想到采用动归的方法,poj1189和poj1322都是采用动归去求概率,每次进行模拟。用dp[i][j]表示第i次剩j个巧克力的概率,那么dp[i][j]可求dp[i - 1][j - 1] 和 dp[i - 1][j + 1]来转移。
如果第i次取到了和以前相同的颜色,那么就由dp[i -1][j + 1] * (j + 1) / color_number,如果没有取到相同的颜色,就由dp[i - 1][j - 1] * (color_number - j + 1) / color_number;
poj1936:添加最少的字符使一个串成为回文的串,dp[i][j]表示从i到j所需要添加的最少的字母。如果str[i] = str[j],那么dp[i][j] = dp[i + 1][j - 1].如果不等的话就dp[i][j] = min(dp[i][j - 1],dp[i + 1][j]) + 1
hdu4165:有N个药片,每天可以选半片或者一整片然后分成办片。求所有方法数.采取动态规划,dp[i][j]表示剩i个完整药片和j个办片药的方法数。那么dp[i][j] = dp[i - 1][j + 1] + dp[i][j - 1].
注意边界初始化。首先i为0的时候肯定是只有一种方法,j为0的时候,只有一种状态转移,所以每次算i的时候都要初始化一下dp[i][0] = dp[i - 1][1];
或者直接是卡特兰数.Catalan数,有四种经典的组合问题可以用它去解。一:长度为2n的词,只含XY,其中X有n个,Y有n个。求组合在所有词的前缀之中,X的个数不多于Y的个数。药片这题就是这样。
或者是走矩形,或者是有n个人有5元,n个人10元,然后都去买东西,问有多少种组合商家能够找开钱。同样也是10元的个数不多于5元的个数。
Catalan的简单递归公式为:number[i] = number[i - 1] * (4 * i - 2) / (i + 1),很大,可能爆的话可以先除一下。
poj2411:状态压缩,用二进制位来表示状态,状态的转移方程一般是相容状态之间的一种转移。
用二进制来表示木快放的方式,横放为两个1,竖放为竖着的10。那么当前行只要考虑上一行的状态。如果和上一行相容的话就进行转移,如果不相容的话就不进行转移。
如果判断相容?如果当前行当前列j为1,如果上一行也为1的话说明两行的第j + 1列也一定是1,如果不是1的话肯定不相容。
如果当前行当前列为0的话,说明上一行一定不为0,如果为0的话则不相容。如果所有列不矛盾的话,说明都满足,则说明状态相容。
那么就可以进行转移。
uva103:求最长路,状态转移dp[i]表示以i为起点能达到的最长路。
状态转移就是dp[i] = max(dp[u] + 1),如果i->u的话。
初始话,出度为0的点表示不能转移,所以dp[i] = 1;
uva10003:用dp[i][j]来表示切第i段到第j段所需要的最少花费。可增加虚点,左端点为0,右端点为整个长度。
则答案为dp[0][cut_number + 1]。
转移方程就是dp[i][j] = min(dp[i][k] + dp[k][j]) (i + 1 <= k <= j - 1)。
初始化dp[i][i] = dp[i][i + 1] = 0;
uva10062:水,最长公共子序列变形。
uva10192:水,最长公共子序列。
uva147:找硬币,老问题了。dp[i][j] = dp[i - 1][j - k * coin[i]] (k * coin[i] <= j);
优化一下,i只和i - 1有关系。所以可以写成dp[j] = dp[j - coin[i]];
uva357:同uva147.
uva562:划分硬币,将一堆硬币划分成两块。没有思路。看解题报告才知道转移方程。对每一个硬币进行划分,相当于0-1背包问题,取或者不取。用dp[i]表示第一个人可以有i的钱。
如果dp[i] = 1,那么dp[i + coin[k]] = 1;唯一注意的是0-1背包需要逆序去推。
并且两个人分钱分尽可能均匀的话一定是在sum / 2附近。最后在sum / 2附近找到dp[i] = 1即可。
uva348:裸的矩阵链。dp[i][j] = dp[i][k] + dp[k + 1][j] + row[i - 1] * row[k] * row[j],划一下矩阵形式就知道。
uva624:和uva562一样,0-1背包。唯一不同的是需要输出方案。用pre[i]来表示第i钱取的话,硬币的种类。为了防止当前状态对上一个状态的影响,pre[i]只能取一次。
然后找到最大的能分的方案。依次输出即可。
uva10130:裸的0-1背包
uva531:最长公共子序列。字符换成了单词。
uva10465:给定容量,以及两个物品,每个物品的重量,求最多能装多少物品数。
完全背包。
uva437:正方体嵌套问题,求最长路。
uva10404:博弈问题,令dp[i]表示先手是否胜,dp[i] = 1表示先手胜,dp[i] = 0表示后手胜。dp[i]的转移可以依据取的数目来转移。如果所有转移都是先手胜的话,那么dp[i] = 0;
否则dp[i] = 1;
uva825:计算总方法数:dp[i][j] = dp[i][j - 1] + dp[i - 1][j],如果(i,j-1),(i - 1, j)可以通过,否则哪个不能通过就不加哪个。dp[1][1] = 1;
uva10069:刚开始自己写的超时了,一开始思路:令dp[i][j]表示处理到串2第i个字符,匹配到串1的第j个字符。那么dp[i][j] += dp[i - 1][k](k < j).其中i - 1可以匹配到
第k个字符。先预处理一下,找到串2每个字符可以匹配到串1的各个字符。最终复杂度为O(n ^ 2 * m),对于10000的复杂度来说还是大了一些。
并且最多可以有10 ^ 100个子串,需要用高精度来保存。
网上搜了报告,dp[i][j]表示串1前i个字符和串2前j个字符子串的方法数。dp[i][j]一定比dp[i - 1][j]大。
如果string_1[i] != string_2[j]的话,说明串1的第i个字符没有用,那么dp[i][j] = dp[i - 1][j];
否则的话dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j];
uva10534:求一遍最长上升和一遍最长下降,然后枚举,枚举到每个点时取最长上升和最长下降的较小值,较大的一定可以满足较小的。另外朴素的求最长上升是n ^ 2,但是有nlogn的算法,
见模板。
uva10651:状态压缩,最多2048个状态,有石头表示1,空洞表示0,先求出不能进行转移的状态。然后根据当前状态进行转移,求最小值。
uva10635:最长上升子序列,因为若按照最长公共子串求的话是pq的复杂度。但是我们可以令串1各个数字编号为1 - (q + 1),然后串2的各个数字,如果存在的话就是串1的号,如果
不存在的话就是0或者-1都无所谓,表示不存在。那么求的最长公共的话一定是最长上升序列,因为串1是上升的,且不存在的用0表示了。
poj1260:用dp[i]来表示处理第i个珍珠,因为对于第i个品质的珍珠,要么自己买,要么前面的珍珠和他一起湊过来买。所以状态转移方程为:dp[i] = min{dp[j] + (sums[i] - sums[j] + 10) * price[i]};其中(0<j<i),二重循环解决问题。
poj1018:首先会定义一个状态dp[i]来表示处理第i件物品,然而第i件物品的转移要依据前面的物理,会违背无后效性的原则,所以还需要增加定义一个状态来表示处理第i件物品时前i - 1件物品的最小带宽。
那么dp[i][j]应该代表什么呢?一开始已经想到了前面二维状态的代表,而没有想到dp[i][j]应该代表什么。而应该的想法是既然最小带宽已经被表示了,为了求到最大的B / P的话,B是已经知道的。所以我们
应该使dp[i][j]代表处理第I件物品,最小带宽为j的最小总价格,因为最小带宽只能够从输入设备那里面得到,所以还需要用dp[i][j] = -1来表示没有该最小带宽。那么状态方程就可以表示成dp[i][j] = min(dp[i - 1][k] + price[k]) (其中dp[i - 1][k]因该首先
是可以达到的,然后可以达到之后,进行状态的转移,可以转到dp[i][k],如果第m件产品的带宽比该最小带宽大,或者是转移到dp[i][min],表示第m件产品的带宽比最小带宽小)。最后枚举所有可能的最小带宽,求
其中的最大值。
poj1050:最大矩阵和,直接枚举,从i到j行,假设是最大矩阵和所在的行数,那么问题就划分成为了最大数组和,直接采用O(n)的算法求得最大数组和,即可输出答案。
poj1083:记录区间重叠数,可以采用一个vis数组,从vis[start]记录到vis[end],每次vis[k]++即可,然后找出最大的重叠数,找出来之后则是最大的不能并行移动的桌子数目,则最后乘以10输出答案。
poj1125:Floyd算法,计算次序很重要,k最先被计算,然后依次是I和J.如果存在d[i][j] = INF的话,表明i到j之间不存在联通的路
poj1178:Floyd算法,题意是有很多个骑士,然后有一个国王,他们现在都要移动要某一个方格里面,如果一个骑士在中途碰见国王的话,可以带着国王一起走,相当于国家不要再移动了。
没有思路怎么去做。1:不知道在哪个点汇合,2:不知道在哪个点骑士会碰见国王。3:不知道是哪个骑士会被碰见国王。如果有很多未知情况的话,第一要看数据范围,看能不能进行枚举。
如果可以采取枚举的话,就去枚举。而本题的数据范围为64 * 64 * 64,明显可以采用枚举的方法。进行一次预处理。如果知道了哪个点汇合,哪个点骑士碰见国王,哪个骑士碰见国王的话,则骑士应该
采取最小步骤跳到国王那,国王应该采取最小步骤跳到中间步骤那,骑士应该采取最小步骤跳到终点,所以是一个最短路径的算法。而利用了枚举,所以很明显的要采取Floyd算法来计算任意两点之间的
路径。
poj1189:求选去一些钉子之后道尔顿板落到第I个格子的概率,如果第n层的i个格子摘去的话,则从它经过的球直接下落。采取模拟球下落的方法,设number[i][j]为第i层第j个空洞的球数,那么如果
它下面的钉子被摘去的话,number[i][j]个球就直接会落到number[i + 2][j + 1],否则的话number[i][j]就会分散到number[i + 1][j]和number[i + 1][j + 1],最后算出第number[n][m]的球数,除以2^n即可。
因为要输出既约整数,分别除以两个的最大公约数,直接输出。
poj1322:有N种颜色的巧克力,从一个包里面依次拿M次,然后每遇到两个相同颜色的巧克力就吃掉,问最后剩K个巧克力的概率是多大。
没有想到采用动归的方法,poj1189和poj1322都是采用动归去求概率,每次进行模拟。用dp[i][j]表示第i次剩j个巧克力的概率,那么dp[i][j]可求dp[i - 1][j - 1] 和 dp[i - 1][j + 1]来转移。
如果第i次取到了和以前相同的颜色,那么就由dp[i -1][j + 1] * (j + 1) / color_number,如果没有取到相同的颜色,就由dp[i - 1][j - 1] * (color_number - j + 1) / color_number;
poj1936:添加最少的字符使一个串成为回文的串,dp[i][j]表示从i到j所需要添加的最少的字母。如果str[i] = str[j],那么dp[i][j] = dp[i + 1][j - 1].如果不等的话就dp[i][j] = min(dp[i][j - 1],dp[i + 1][j]) + 1
hdu4165:有N个药片,每天可以选半片或者一整片然后分成办片。求所有方法数.采取动态规划,dp[i][j]表示剩i个完整药片和j个办片药的方法数。那么dp[i][j] = dp[i - 1][j + 1] + dp[i][j - 1].
注意边界初始化。首先i为0的时候肯定是只有一种方法,j为0的时候,只有一种状态转移,所以每次算i的时候都要初始化一下dp[i][0] = dp[i - 1][1];
或者直接是卡特兰数.Catalan数,有四种经典的组合问题可以用它去解。一:长度为2n的词,只含XY,其中X有n个,Y有n个。求组合在所有词的前缀之中,X的个数不多于Y的个数。药片这题就是这样。
或者是走矩形,或者是有n个人有5元,n个人10元,然后都去买东西,问有多少种组合商家能够找开钱。同样也是10元的个数不多于5元的个数。
Catalan的简单递归公式为:number[i] = number[i - 1] * (4 * i - 2) / (i + 1),很大,可能爆的话可以先除一下。
poj2411:状态压缩,用二进制位来表示状态,状态的转移方程一般是相容状态之间的一种转移。
用二进制来表示木快放的方式,横放为两个1,竖放为竖着的10。那么当前行只要考虑上一行的状态。如果和上一行相容的话就进行转移,如果不相容的话就不进行转移。
如果判断相容?如果当前行当前列j为1,如果上一行也为1的话说明两行的第j + 1列也一定是1,如果不是1的话肯定不相容。
如果当前行当前列为0的话,说明上一行一定不为0,如果为0的话则不相容。如果所有列不矛盾的话,说明都满足,则说明状态相容。
那么就可以进行转移。
uva103:求最长路,状态转移dp[i]表示以i为起点能达到的最长路。
状态转移就是dp[i] = max(dp[u] + 1),如果i->u的话。
初始话,出度为0的点表示不能转移,所以dp[i] = 1;
uva10003:用dp[i][j]来表示切第i段到第j段所需要的最少花费。可增加虚点,左端点为0,右端点为整个长度。
则答案为dp[0][cut_number + 1]。
转移方程就是dp[i][j] = min(dp[i][k] + dp[k][j]) (i + 1 <= k <= j - 1)。
初始化dp[i][i] = dp[i][i + 1] = 0;
uva10062:水,最长公共子序列变形。
uva10192:水,最长公共子序列。
uva147:找硬币,老问题了。dp[i][j] = dp[i - 1][j - k * coin[i]] (k * coin[i] <= j);
优化一下,i只和i - 1有关系。所以可以写成dp[j] = dp[j - coin[i]];
uva357:同uva147.
uva562:划分硬币,将一堆硬币划分成两块。没有思路。看解题报告才知道转移方程。对每一个硬币进行划分,相当于0-1背包问题,取或者不取。用dp[i]表示第一个人可以有i的钱。
如果dp[i] = 1,那么dp[i + coin[k]] = 1;唯一注意的是0-1背包需要逆序去推。
并且两个人分钱分尽可能均匀的话一定是在sum / 2附近。最后在sum / 2附近找到dp[i] = 1即可。
uva348:裸的矩阵链。dp[i][j] = dp[i][k] + dp[k + 1][j] + row[i - 1] * row[k] * row[j],划一下矩阵形式就知道。
uva624:和uva562一样,0-1背包。唯一不同的是需要输出方案。用pre[i]来表示第i钱取的话,硬币的种类。为了防止当前状态对上一个状态的影响,pre[i]只能取一次。
然后找到最大的能分的方案。依次输出即可。
uva10130:裸的0-1背包
uva531:最长公共子序列。字符换成了单词。
uva10465:给定容量,以及两个物品,每个物品的重量,求最多能装多少物品数。
完全背包。
uva437:正方体嵌套问题,求最长路。
uva10404:博弈问题,令dp[i]表示先手是否胜,dp[i] = 1表示先手胜,dp[i] = 0表示后手胜。dp[i]的转移可以依据取的数目来转移。如果所有转移都是先手胜的话,那么dp[i] = 0;
否则dp[i] = 1;
uva825:计算总方法数:dp[i][j] = dp[i][j - 1] + dp[i - 1][j],如果(i,j-1),(i - 1, j)可以通过,否则哪个不能通过就不加哪个。dp[1][1] = 1;
uva10069:刚开始自己写的超时了,一开始思路:令dp[i][j]表示处理到串2第i个字符,匹配到串1的第j个字符。那么dp[i][j] += dp[i - 1][k](k < j).其中i - 1可以匹配到
第k个字符。先预处理一下,找到串2每个字符可以匹配到串1的各个字符。最终复杂度为O(n ^ 2 * m),对于10000的复杂度来说还是大了一些。
并且最多可以有10 ^ 100个子串,需要用高精度来保存。
网上搜了报告,dp[i][j]表示串1前i个字符和串2前j个字符子串的方法数。dp[i][j]一定比dp[i - 1][j]大。
如果string_1[i] != string_2[j]的话,说明串1的第i个字符没有用,那么dp[i][j] = dp[i - 1][j];
否则的话dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j];
uva10534:求一遍最长上升和一遍最长下降,然后枚举,枚举到每个点时取最长上升和最长下降的较小值,较大的一定可以满足较小的。另外朴素的求最长上升是n ^ 2,但是有nlogn的算法,
见模板。
uva10651:状态压缩,最多2048个状态,有石头表示1,空洞表示0,先求出不能进行转移的状态。然后根据当前状态进行转移,求最小值。
uva10635:最长上升子序列,因为若按照最长公共子串求的话是pq的复杂度。但是我们可以令串1各个数字编号为1 - (q + 1),然后串2的各个数字,如果存在的话就是串1的号,如果
不存在的话就是0或者-1都无所谓,表示不存在。那么求的最长公共的话一定是最长上升序列,因为串1是上升的,且不存在的用0表示了。