nk 1207 &&poj 1011

题目链接:http://acm.nankai.edu.cn/p1207.html

题目大意:给你n个数判断利用所给的数字长度是否可以组成正方形,对于一般不成立的数据可以根据长度之和是否为四的倍数,但满足这条件的也不一定是正方形,要进行四条边的判定,即dfs搜索每条边,只有四条边同时成立时才能说明成立,这里需要进行优化,由于和poj 1011相同故这里不再说明,见下文 。

View Code
 1 #include <iostream>
2 #include <cstdio>
3 #include<cstring>
4 using namespace std;
5 int a[25],v[25],w,n;
6 bool dfs(int num,int len,int pos)
7 {
8 int i;
9 bool sign=(len==0)?true:false;
10 if(num==4)return true;
11 for (i=pos+1;i<=n;i++)
12 {
13 if(!a[i]){
14 if (len+v[i]==w)
15 {
16 a[i]=1;
17 if(dfs(num+1,0,0))
18 return true;
19 a[i]=0;
20 return false;
21 }
22 else if (len+v[i]<w)
23 {
24 a[i]=1;
25 if(dfs(num,len+v[i],i))
26 return true;
27 a[i]=0;
28 if(sign)return false;
29 while(v[i]==v[i+1])i++;
30 }
31 }
32 }
33 return false;
34 }
35 int main()
36 {
37 int i,k;
38 scanf("%d",&k);
39 while (k--)
40 {
41 w=0;
42 scanf("%d",&n);
43 for (i=1;i<=n;i++)
44 {
45 scanf("%d",&v[i]);
46 w+=v[i];
47 }
48 if(w%4){cout<<"no"<<endl;continue;}
49 w=w/4;
50 memset(a,0,sizeof(a));
51 if(dfs(1,0,0))cout<<"yes"<<endl;
52 else cout<<"no"<<endl;
53 }
54 return 0;
55 }

poj 1011

题目链接:http://poj.org/problem?id=1011&lang=zh-CN&change=true

题目大意:有许多长度相同的木棍,现在把它锯成许多小段知道每段的长度,但却忘记了原始有多少根以及每根有多长,问把这些木棒连接成长度相同的若干根,求这个最小长度。

解法dfs 但这道题 有许多剪枝,是一道很好的深搜题。

下面是网上列出的剪枝条件比较全,就借来用下。

* 
* 题目大意:给出一些长度不大于 50 的木棍, 要求你把这些小木棍拼成
*             长度相同木棍,当然长度越小越好。
* 解题思路:  思想很简单,一个接一个的把木棍拼起来,最后把木棍用光。
*             关键的地方是几个剪枝技巧:
*                   设所有木棍的总长度为 Sum, 最终的答案(长度)是 L。 
*             1. 首先要明白, Sum一定要能被 L 整除。 
*             2. L 一定 大于等于 题目给出的最长的木棍的长度 Max。
*                  由上述两点,我们想到,可以从 Max 开始递增地枚举 L, 
*                直到成功地拼出 Sum/L 支长度为 L 的木棍。
*                    搜索种的剪枝技巧: 
*             3. 将输入的输入从大到小排序,这么做是因为一支长度为 K 
*                的完整木棍,总比几支短的小木棍拼成的要好。
*                形象一些:
*                  如果我要拼 2 支长为8的木棍,第一支木棍我拼成 
*                          5 + 3
*                  然后拼第二支木棍但是失败了,而我手中还有长为 2 和 1 
*                  的木棍,我可以用 5 + 2 + 1 拼好第一支,再尝试拼第二
*                  支,仔细想一想,就会发现这样做没意义,注定要失败的。     
*                  我们应该留下 2+1 因为 2+1 比 3 更灵活。 
*             4. 相同长度的木棍不要搜索多次, 比如:
*                我手中有一些木棍, 其中有 2 根长为 4 的木棍, 当前搜索
*                状态是 5+4+.... (即表示长度为 5,4,2 的三支拼在一起, 
*                ...表示深层的即将搜索的部分), 进行深搜后不成功,故我
*                没必要用另一个 4 在进行 5+4+...
*             5. 将开始搜索一支长为 L 的木棍时,我们总是以当前最长的未
*                被使用的 木棍开始,如果搜索不成功,那么以比它短的开始
*                那么也一定不能取得全局的成功。因为每一支题目给出的木棍
*                都要被用到。
*                如果,有 
*                    4
*                    5 4 4 3 2
*                  想拼成长为 6 的木棍,那么从 5 开始, 但是显然没有能与 5
*                  一起拼成 6 的,那么我就没必要去尝试从 4 开始的,因为
*                  最终 5 一定会被遗弃。在拼第 2 3 ... 支木棍时,一样。 
*             6. 最后的最简单的一个就是,
*                      for(int i = 0; i < n; i++)
*                          for(int j = 0; j < n; j++)
*                               {}
*                与
*                      for(int i = 0; i < n; i++)
*                          for(int j = i+1; j < n; j++)
*                               {} 
*                的区别,这个不多说了。
*             7. 我用过的另一个剪枝,但是对 poj 的数据效果一般,
*                用一个数组, Sum[i] 保存 第 i 个木棍之后,即比第 i 枝
*                木棍短或与之相等所有的木棍的长度之和。
*                试想,如果剩余的所有木棍加在一起都不能和我当前的状态拼
*                出一直长为 L 的木棍(从长度来看),还有必要搜下去么? 
*/            

View Code
 1 #include<cstdio>
2 #include<cstring>
3 #include<cstdlib>
4 #include<iostream>
5 #include<algorithm>
6 using namespace std;
7
8 const int maxn=70;
9 int n,sum,ma,aim,num,a[maxn];
10 bool used[maxn];
11 int cmp(int x,int y)
12 {
13 if(x>y)return 1;
14 else return 0;
15 }
16
17 bool dfs(int Stick,int len,int pos)
18 {
19 int i;
20 bool sign=(len==0?true:false);
21 if(Stick==num)
22 return true;
23 for(i=pos+1;i<n;i++)
24 {
25 if(used[i]) continue;
26 if(len+a[i]==aim)
27 {
28 used[i]=true;
29 if(dfs(Stick+1,0,-1))
30 return true;
31 used[i]=false;
32 return false;
33 }
34 else if(len+a[i]<aim)
35 {
36 used[i]=true;
37 if(dfs(Stick,len+a[i],i))
38 return true;
39 used[i]=false;
40 if(sign) return false;
41 while(a[i]==a[i+1]) i++;
42 }
43 }
44 return false;
45 }
46 int main()
47 {
48
49 while(scanf("%d",&n)==1)
50 {
51 if(n==0) break;
52 ma=sum=0;
53 for(int i=0;i<n;i++)
54 {
55 scanf("%d",&a[i]);
56 sum+=a[i];
57 if(a[i]>ma) ma=a[i];
58 }
59
60 sort(a,a+n,cmp);
61
62 for(aim=ma;aim<=sum;aim++)
63 if(sum%aim==0)
64 {
65 num=sum/aim;
66 memset(used,false,sizeof(used));
67 if(dfs(1,0,-1))
68 {
69 printf("%d\n",aim);
70 break;
71 }
72 }
73 }
74
75 return 0;
76 }
posted @ 2011-08-07 14:40  我们一直在努力  阅读(532)  评论(0编辑  收藏  举报