题目链接: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