题解 P1120 【小木棍 [数据加强版]】

林则徐

2017-12-15 17:40:43

Solution

暴搜的思路并不难想到,主要难点是各种优化、各种剪枝: 1. 预先处理出所有木棍的总长度,且保证枚举答案的值能被总长度整除。 2. 每根木棍的长度可用桶来存储,并且预先处理出最长的和最短的木棍的长度,搜索时从最大长度到最小长度递减枚举。 3. 若拼接当前木棍时已用了一根长为X的木棍,则dfs时从长度X开始搜索。 4. 若某组拼接不成立,且此时 已拼接的长度为0 或 当前已拼接的长度与刚才枚举的长度之和为最终枚举的答案 时,则可直接跳出循环,因为此时继续枚举其它更小的值时,显然可能情况更少,且同样凑不完。 5. 注意常数不要太大。 附上代码: ```cpp #include<cstdio> #include<cstdlib> const int N = 70 ; int n , cnt , tot , maxn , minn , tm[ N ] /* 2 */ ; void dfs( int res , int sum , int target , int p ) { if( res == 0 ) { printf("%d", target ); exit( 0 ); } if( sum == target ) { dfs( res - 1 , 0 , target , maxn ); return; } for( int i = p ; i >= minn ; i -- ) { // 2 3 if( tm[ i ] && i + sum <= target ) { tm[ i ] -- ; dfs( res , sum + i , target , i ); tm[ i ] ++ ; if ( sum == 0 || sum + i == target ) //4 break; } } return; } int main() { scanf("%d" , &n ) ; minn = N ; int temp; while( n -- ) { scanf("%d" , &temp ); if( temp <= 50 ) { cnt ++; tm[ temp ] ++; tot += temp; maxn = maxn > temp ? maxn : temp ; //1 minn = minn < temp ? minn : temp ; } } temp = tot >> 1; for( int i = maxn ; i <= temp ; i ++ ) { if( tot % i == 0 ) { dfs( tot / i , 0 , i , maxn ); } } printf("%d" , tot ); return 0; } ```