1. 程式人生 > >hdu 1455 sticks【dfs】+經典剪枝

hdu 1455 sticks【dfs】+經典剪枝

ems clas .net tdi pac target 構建 algorithm stream

題目鏈接:https://vjudge.net/problem/HDU-1455

轉載於:>>>>>>

題目大意:

George把一些等長的樹枝切成了n個長度不超過50的短樹枝,現在給你這些短樹枝的長度,計算出原來樹枝的最小長度。

解題分析:
以下是幾種主要的剪枝:

1、這些樹枝的原長度一定大於短樹枝的最大長度,同時也是小樹枝總長度的因子,這個作為初步剪枝。

2、把樹枝從大到小排序,開始匹配一根新的樹枝的時候,如果第一根就不符合結果,那麽後面的結果一定也不符合,很重要的一步剪枝,決定了代碼從TLE到0msAC。

3、排序後的樹枝,如果當前樹枝不滿足,就跳過後面所有等長的樹枝。

#include<cstdio>  
#include<cstring>  
#include<iostream>  
#include<algorithm>  
using namespace std;
int a[70], n, fp;
bool vis[70];
bool cmp(int a, int b) {
    return a>b;
}
void dfs(int pos, int len, int g, int num) {//當前下標、當前長度、目標長度、已匹配數量  
    if (fp)return;
    if (num == n) {//
所有樹枝都匹配上了,說明有解 fp = 1; return; } for (int i = pos; i<n; ++i) { if (!vis[i] && a[i] + len <= g) { vis[i] = 1; if (a[i] + len == g) { dfs(0, 0, g, num + 1); //如果這跟木棍已經構建好了,則pos重置為0,從0開始重新遍歷 }
else { dfs(i + 1, a[i] + len, g, num + 1); } vis[i] = 0;//去除標記 if (fp)return;//找到了結果,返回 if (len == 0)return; //開始匹配一根新的樹枝的時候,如果第一根就不符合結果,那麽後面的結果一定也不符合 while (i<n&&a[i + 1] == a[i])++i;//排序後的樹枝,如果當前樹枝不滿足,就跳過後面所有等長的樹枝。 } } } int main() { int sum; while (scanf("%d", &n), n) { memset(vis, 0, sizeof(vis)); sum = 0; for (int i = 0; i<n; ++i) { scanf("%d", &a[i]); sum += a[i]; } sort(a, a + n, cmp);//從大到小排序,搜索的時候優先選擇大的,減少沖突的情況 for (int i = a[0]; i <= sum; ++i) { if (i == sum)printf("%d\n", sum);//剪枝 else if (sum%i == 0) {//剪枝1 fp = 0; dfs(0, 0, i, 0); if (fp == 1) { printf("%d\n", i); break; } } } } return 0; }

2018-05-25

hdu 1455 sticks【dfs】+經典剪枝