POJ3352 Road Construction / POJ3177 Redundant Paths

题意

给你一个联通图,问你最少要添加多少条边才能把这个图变成一个双联通图。

思路

非常经典的边双联通分量缩点问题。找出图中所有的边双联通分量,把这些分量各自收缩为一个点,节点之间若有边,一定是割边,这样就得到了一棵由边联通分量缩成的点和割边组成的树,把一个树变成双联通图要添加的最少边数是(r+1)/2其中r是这棵树的节点数量,这是一个蛮重要的结论。

找边联通分量的方法有好多,可以找到所有割边之后,对于每个点启动一次dfs,搜索中屏蔽掉所有割边,这样就可以收割所有的边双联通分量,也可以对于每个点直接启动一次tarjan算法,在函数返回的过程中,收割掉所有low值一样的节点就可以得到边双联通分量。这份代码使用的是后一种方案。

代码

两个题一个数据中有重边,一个没有,这份代码考虑了这个问题,所以连边都能顺利过,双倍经验。

 

POJ 2909 Goldbach's Conjecture

題意

給你個數,讓你求出有多少種素數的組合使得兩個素數的和等於給你的這個數。數據範圍比較小,小於等於32768.

思路

沒啥好的數學辦法,但是數據範圍比較小,所以不妨嘗試打個素數表看看小於32768的素數有多少,打完了發現就3000多個,這樣的話即使是O(n^2)的時間複雜度也沒有問題。我們開個計數器數組,然後枚舉素數和,加到計數器上面,預處理好這些之後,直接受理查詢就可以了。

代碼

 

POJ 3744 Scout YYF I

题意

某人在直线上走,直线上有若干格子,起点是1号格,每次这个人都有p概率走1格,1-p概率走二格,有一些格子有地雷,走上去就被爆了,所以要你求你能安全走到终点(可以看成是站在n+1号格)上概率。

思路

每一个格子的概率都可以通过它前两个的格子的概率推出来,这样的话跟斐波那契很像。
联想我们想快速地搞出来一个非常大的fib值的方法是什么?快速幂。
所以这个题我们用快速幂来做。

dp方程其实都不叫dp,叫递推,大概长这个样子:

\begin{bmatrix}p&1-p\\1&0 \end{bmatrix}\begin{bmatrix}p_{n} \\ p_{n-1}\end{bmatrix}=\begin{bmatrix} p_{n+1}\\p_{n}\end{bmatrix}

直接矩阵乘法模版+快速幂就行。

处理地雷的话,你就先走到地雷那里,停一下,把地雷格的dp值抹成0,然后继续往下走,走到下一个地雷,最后走到终点。

代码

 

POJ 2096 Collecting Bugs

题意

给软件挑bug,每天挑出来一个,每个bug都有两个属性:分类和子系统,这两个属性都是完全随机的,已知一共有n个分类,s个子系统,问你挑出的bug完全覆盖全部分类和子系统需要多长时间(求期望)。

思路

优惠券问题的变种,相当于升高到了二维,因此dp数组也要开成二维。

我们设定dp[i][j]表示距离完成任务还有i个分类j个子系统没有覆盖,状态的转移用如下几种:
1.挑出的bug属于全新的分类和子系统
2.挑出的bug仅仅属于全新的分类
3.挑出的bug仅仅属于全新的子系统
4.挑出的bug没有任何新意
这样,我们可以得出状态转移方程:dp[i][j]=\frac{i}{n}\frac{j}{s}dp[i-1][j-1]+\frac{n-i}{n}\frac{j}{s}dp[i][j-1]+\frac{i}{n}\frac{n-j}{s}dp[i-1][j]+\frac{n-i}{n}\frac{n-j}{s}dp[i][j]+1

经过化简可以发现这是个很直接的递推方程了,所以可以很轻松的出答案了。

代码

 

POJ 3488 Arne Saknussemm

题意

这个题的目的是练习读题,所以请努力理解这个题的题意,这里故意不翻译,it’s good for you~。

思路

操作时需要注意,string对象的结束位置并不是像char数组那样用’\0‘标记的,除非string对象被重做,否则这个对象的size值不会改变,即使你把一个string对象的每个字符全都弄成’\0’,你输出的也不是空串,而是一堆不可见的’\0’。

如果这个题很神秘的WA到死,请检查一下是不是跪在了不可见字符上。

代码

 

POJ 1019 Number Sequence

题意

11212312341234512345612345671234567812345678912345678910123456789101112345678910…
让你求这么一个丧心病狂的数列第i位是啥。

思路

找规律,我们可以把数列切割为1/12/123/1234/…这样我们可以想办法求出每一段的控制范围,然后对于给出的i,先快速确定这个i会落在哪一个数的控制范围里面,是第几个,然后再想办法快速确定在这个控制范围内i到底对应了哪个数,我写的比较恶心(很长),其实在纸上试着写一些应该是能发现具体的规律和算法的。

代码

 

POJ 3685 Matrix

题意

好像是《挑战程序设计竞赛》上面的原题。题意是给你一个矩阵上每一项的位置与值对应的公式,让你求第k小的项。

思路

我们仔细看公式会发现对于每一个固定的j,公式结果随i单调递增,这样我们可以二分答案,对于mid值,我们在每一列再二分一次,求出比这个数小的数的个数,然后每一列的个数相加,就是这个数的排名。然后这个排名可以作为二分中判定的基准。这里还有一种替代思路,就是对于每一列不二分,而是解一个二次方程直接求出每一列的分排名。

代码

 

POJ 3740 Easy Finding

搜索题,但是BFS不可以,DFS的话优化还特别寸,写了几个版本都过不了,挺邪乎的。

PS:好长时间没做题,想必是遭了报应了。

POJ 3624 Charm Bracelet 顺便讲一下01背包

裸的01背包问题,是DP的基础题型了,没有太多好说的。

简要说一下01背包问题的状态转移特点:按两个基准纪录数据,第一个基准是我们从0~a号物品中选,第二个基准是选择的物品已经有了多少重量b,这样组成了dp数组dp[a][b],这个数组存储的是当前状态的价值是多少。接下来我们开始dp,对于每一个当前状态(最多选择到第n个物品,已经占用了w重量),我们是从两种先前状态中导出的:1.最多选择到n-1个物品(就是当前物品还没有考虑呢),占用重量w-x(x是第n个物品重量),在这个状态上,我们添加上第n个物品。2.最多选择到n-1个物品,占用重量w,在这个状态上,我们什么也不做,直接把他当成当前状态。

在这两种先前状态中选择最好的那个(有时候因为某些原因,只能选择一个,那就选唯一的那个就好),保存下来决定为当前状态,再供以后使用。

这样我们只要读取dp[i][j]的值,就是“选择1~i中的物品,重量限定为j,最高价值是?”这个问题的答案。(没有用滚动数组的话)

POJ 1062 昂贵的聘礼

这个题是一个比较基准有些多的最短路(和之前那个Dirt挺像)。

(这里的cost就是dijkstra算法里面的dis值)每一次更新下一节点时,下一节点的cost值为(当前cost值-当前点权+下一边边权+下一点点权);每一次到达节点后,都根据当前抽出的节点的地位值,更新当前走过节点的地位的最大最小值,等接下来更新临接节点时,如果下一节点的地位与当前最大最小值中任意一个只差绝对值>m就要抛弃。以这两个为基准,进行正常的dijkstra,然后从头到尾的扫一遍cost数组,把最小值输出来就是答案。

Scroll to top