之所以要写这两题的解题报告,原因就是这两题是比较好的搜索题,必须记录一下。
另外,最近做题状态也不行,看见题目后没想法,然后看别人解题报告了,突然发现自己想过这方面,但是没深入去想,然后就做不出来了。
1.POJ 1010 题意晦涩难懂。从网上找了一个稍微能说清楚的题意
题意:
给出n种邮票,每种邮票有自己的面值(面值可能重复)
指定m种“总面值”,对每种“总面值”,求解满足如下条件的组合以达到该“总面值”
(1) 所用邮票在n种中可以重复选取
(2) 所用邮票张数〈=4
(3) 尽量多的使用那个不同种类的邮票 Max (Stamp Types)
(4) 若有多种方案满足(3),则选取张数最小的一种方案 Min (Stamp Num)
(5) 若有多种方案满足(3)(4),则选取“最大面额”最高的一种方案。 Max(Heightest Value)
(6) 若有多种方案满足(3)(4)(5) 则输出 “tie”1010
并且这题给的sample都还夹着注释,不仔细看题还以为那些也需要输入。
说一下思路吧,动态规划是最优选择,但是确实不好想,普遍的都是用DFS。
优化之一: 每种面值的邮票最多5种即可,如果有多的,就不需要了。比如一下子给了1 1 1 1 1 1 1 1,八个1,其实只需要5个就行,因为题目说了,最多4个,保留5个的目的就是为了多解准备的。再多也没意义。这样由于最多有25种邮票,也就是数组到126就够了。
然后dfs过程中如果选择的邮票面额之和大于所需的,也剪掉,总数大于4的剪掉,剩下的貌似就没什么了。
dfs过程中,有一个中间值,存储着邮票的种类,总个数,最大面值,所选的邮票等,然后有一个最终结果,每次dfs出的中间值,如果优于最终结果就要更新最终结果,那么怎样算是tie呢,就要用1个变量标记一下,如果被更新了,就置这个变量为1,如果出现打平的,就把他++一下,这样不断的覆盖这个变量即可。
另外,这道题目貌似给的序列都是有序的。
/*
ID: sdj22251
PROG: subset
LANG: C++
*/
#include
#include
#include
#include
2.poj 1020
又是一道搜索题
题目大意是给出一个大的正方形,然后又给出了一群小正方形,问大的正方形能不能由这些小正方形组成,并且每个正方形都要用到。
思路是贪心+dfs
首先,对输入的数组,由于题目中说了,小正方形的边长范围是1~10,所以开个数组记录一下每个边长的正方形个数,dfs的时候枚举就方便了。
然后用一个数组,len[i]表示第i行被覆盖了len[i]列,而且是左边无空隙的。
然后每次贪心找最小的len[i],因为这样的话,达到最优解的可行性最大。在这个位置上,看下面和右面是否有足够的位置,前提是左边是填充好的,所以就要求这些位置的len[i]必须都是一样的,然后就枚举边长,往里塞小正方形,找不到解就回溯。
网上有的贪心是不正确的,因为没有考虑到一些比较特别的数据,而且poj的这道题数据还很弱。正确的做法应该是贪心+回溯,就能保证一定要到正确的答案。
/*
ID: sdj22251
PROG: subset
LANG: C++
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define MAXN 100007
#define INF 1000000000
#define eps 1e-7
using namespace std;
int n, x;
int len[55], cnt[15];
bool dfs(int deep)
{if(deep &#61;&#61; n) return true;int mi &#61; INF;int pos &#61; 0;for(int i &#61; 1; i <&#61; x; i&#43;&#43;){if(mi > len[i]){mi &#61; len[i];pos &#61; i;}}for(int i &#61; 1; i <&#61; 10; i&#43;&#43;){if(cnt[i]){if(len[pos] &#43; i <&#61; x){int width &#61; 0;for(int j &#61; pos; j <&#61; x; j&#43;&#43;)if(len[j] &#61;&#61; len[pos]) width&#43;&#43;;else break;if(width >&#61; i){cnt[i]--;for(int j &#61; pos; j }
int main()
{int T;scanf("%d", &T);while(T--){scanf("%d", &x);memset(len, 0, sizeof(len));memset(cnt, 0, sizeof(cnt));scanf("%d", &n);int area &#61; 0, t;for(int i &#61; 0; i }