您的位置:首页 > 其它

hdoj 1455 && nyoj 293 && poj 1110 Sticks 【DFS + 剪枝 + 剪枝 + 剪枝 + 。。。+ 剪枝】

2015-06-21 14:04 531 查看


Sticks

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)

Total Submission(s): 7380 Accepted Submission(s): 2170



Problem Description
George took sticks of the same length and cut them randomly until all parts became at most 50 units long. Now he wants to return sticks to the original state, but he forgot how many sticks he had originally and how long they were
originally. Please help him and design a program which computes the smallest possible original length of those sticks. All lengths expressed in units are integers greater than zero.



Input
The input contains blocks of 2 lines. The first line contains the number of sticks parts after cutting, there are at most 64 sticks. The second line contains the lengths of those parts separated by the space. The last line of the
file contains zero.



Output
The output file contains the smallest possible length of original sticks, one per line.



Sample Input
9
5 2 1 5 2 1 5 2 1
4
1 2 3 4
0




Sample Output
6
5



把三个OJ题目做了之后自己要崩溃。。。 先是0ms过hdoj,nyoj,poj超时,再是2352ms过nyoj,poj超时,最后0ms过poj。。。

思路:剪枝点有5个 对应代码里面给出的剪枝1,剪枝2,剪枝3,剪枝4,剪枝5

1,当前木条匹配失败,后面和它等长度的不能再用了,这个比较好想;
2,木条要降序排列,因为越长的约束力越大,当用一堆较短的木条构成的长度接近平均长度时,你用更大去匹配显然不行,这样会白白浪费很多时间;
3,最最重要的一点:要想得到最后的解,匹配每一组的第一个木条必须要成功,因为第一个不成功后面就不用想了;
4,在匹配完一组时,继续下一组时匹配,若是失败直接返回,因为中间若断了,最后也不能成功;
5,这一剪枝不太重要,但是还是说一下吧:枚举长度时,从最大的开始枚举,这一点不解释自己想。

hdoj poj :0ms nyoj :2324 ms

AC代码
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int stick[65];
int n;
int every;//每组木条应有长度
bool vis[65];//标记当前木条是否用过 
int total;//应成组数 
bool cmp(int a, int b)//剪枝2: 降序排列 
{
	return a > b;
} 
int DFS(int match, int len, int pos)//match已成组数 len当前组已配长度  pos当前搜索位置 
{
	if(match == total)//已成组数 等于 应成组数 
	return 1;
	else
	{
		for(int i = pos; i < n; i++)
		{
			if(vis[i]) continue;//已经用过 
			if(len + stick[i] == every)//正好配成一组 
			{
				vis[i] = true;
				if(DFS(match+1, 0, 0)) return 1;//继续配对下一组 
				vis[i] = false;//下一组配失败  
				return 0;//剪枝4: 不用进行下面的匹配了  
			} 
			if(len + stick[i] < every)
			{
				vis[i] = true;
				if(DFS(match, len+stick[i], i+1)) return 1;
				vis[i] = false;
				if(len == 0)//剪枝3: 匹配第一根木条就失败 后面的也不用匹配了
			    return 0;
				while(stick[i] == stick[i+1])//剪枝1: 匹配失败 后面与它同长度的也不行  
				++i;
			} 
		} 
	}
	return 0;
} 
int main()
{
	int i, sum;
	while(scanf("%d", &n), n)
	{
		for(i = 0, sum = 0; i < n; i++)
		{
			scanf("%d", &stick[i]);
			sum += stick[i];
		}
	    sort(stick, stick+n, cmp);
		for(every = stick[0]; every <= sum; every++)//剪枝5:从最长的木条开始遍历每组可能长度 
		{
			if(sum % every) continue;//不能整除 
			total = sum / every;//应成组数  
			memset(vis, false, sizeof(vis)); 
			if(DFS(0, 0, 0))
			{
				printf("%d\n", every);
				break;
			}
		} 
	}
	return 0;
}

大神8ms代码:醉了醉了 实在忍不住看了下,大牛别不要怪我。。。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define  L  64

int cutnum;                 // 木棍的数量
int cutlen[ L ], totlen;    // 木棍的各自长度,及总长度

int cmp( const void *pa, const void *pb) {
        return (*((int*)pb)) - (*((int*)pa));
}

int orglen, orgnum; // 原始木棍的长度及其数量
int used[ L ];      // dfs 时标记某木棍是否已经被用于组装原始木棍
//int choice[ L ];

// 若搜索次数超过此值,则认为不可能成功
#define  LIM  100000
int lim;
        // 尝试拼装某原始木棍,
        // 此次尝试之前,
        // 已经使用了 t 根木棍,
        // 已经拼装出了原始木棍的部分长度,剩余 c 长度需要拼装,
        // 此次尝试,只需要从第 b 根木棍开始。
int dfs(int c, int b, int t) {
        int i, prelen = -1;
        if ( --lim <= 0 ) {
                return 0;
        }
        if ( 0 == c ) {
                // 剩余长度为 0,则开始拼装下一根原始木棍,
                // 需扩大尝试的范围。
                for ( i = 0; (i < cutnum) && (used[i]); ++i ) {
                }
                // 所有木棍都已经被用于拼装原始木棍,
                // 即尝试成功。
                if ( i >= cutnum ) {
                        //printf("i >= cutnum, t = %d\n", t);
                        return 1;
                }
                used[ i ] = 1;
                //choice[ t ] = i;
                // 任一原始木棍中,必含有剩余木棍中最长的那根
                if ( dfs(orglen-cutlen[i], i+1, t+1) ) {
                        return 1;
                }
                used[ i ] = 0;
                return 0;
        }
        for ( i = b; i < cutnum; ++i ) {
                if (    (used[ i ]) ||          // 木棍没用过
                     (prelen == cutlen[i]) ||   // 此长度的木棍已经试过,不行,无需再试
                        (c < cutlen[i])      // 剩余长度能容纳此木棍
                ) {
                        continue;
                }
                used[ i ] = 1;
                //choice[ t ] = i;

                // 下次尝试从后面的木棍开始,前面的木棍无需考虑
                if ( dfs(c-cutlen[i], i+1, t+1) ) {
                        return 1;
                }

                prelen = cutlen[ i ];

                used[ i ] = 0;

                // 存在一木棍刚好可以符合剩余长度,则不再尝试其它
                if ( c == cutlen[ i ] ) {
                        return 0;
                }
        }
        return 0;
}

int find(){
        // 原始木棍长度必为总长度的约数
        if ( 0 != totlen % orglen ) {
                return 0;
        }
        orgnum = totlen / orglen;
        memset(used, 0, sizeof(used));
        lim = LIM;
        return dfs(0, 0, 0);
}

int main() {
        int i;
        while ( (1 == scanf("%d", &cutnum)) && (0 < cutnum) ) {
                totlen = 0;
                for ( i = 0; i < cutnum; ++i ) {
                        scanf("%d", cutlen+i);
                        totlen += cutlen[ i ];
                }
                // 将木棍从长到短排序,然后从长到短搜索之
                qsort(cutlen, cutnum, sizeof(cutlen[0]), cmp);

                /**//*for ( i = 0; i < cutnum; ++i ) {
                        printf("-%d-", cutlen[ i ]);
                }
                printf("\n");*/

                // 原始木棍长度必大于等于最长木棍长度,
                // 小于等于木棍总长度,
                // 从短到长枚举原始木棍长度。
                for ( orglen = cutlen[0]; (orglen < totlen) && (! find()); ++orglen ) {
                }
                printf("%d\n", orglen);
                //if ( orglen != totlen ) {
                //        for ( i = 0; i < cutnum; ++i ) {
                //                printf("--%d--", choice[ i ]);
                //        }
                //        printf("\n");
                //}
        }
        return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: