zoukankan      html  css  js  c++  java
  • UVa 307

    Sticks 

    【题目链接】:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=24&page=show_problem&problem=243

    【 随 笔 】:很久之前就遇到这道题,题目意思容易理解,后来自己想到了一个法子,思路也很清晰就将代码敲出来了,用了位运算(后来问师兄是说状态压缩,其实我不知道什么是状态压缩~_~),不过提交的时候超时了,我想着优化代码,尽可能加剪枝的条件,却无从下手,后来搜题解搜到了师兄的博客,题解中剪枝的条件自己能想到的五个中了三个,剩下两个剪枝也容易理解,整个DFS的思路也容易理解,这点值得反思,其中的原因我想是自己先入为主了,在之前的思路上瞎折腾,未果却也不接受考虑另外的可能,其实看了师兄的代码思路后,也就是普普通通的暴力回溯,不多说,先保存TL的代码:

    【AC的代码链接】:http://www.cppblog.com/y346491470/articles/155318.html

    【超时的代码】

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<string>
     4 #include<cstring>
     5 #define MAXN 500
     6 using namespace std;
     7 int sticks[MAXN];
     8 bool visit[MAXN];
     9 int n, sumlen, res;
    10 
    11 bool judge(int fac)
    12 {
    13     int i;
    14     for(i=0; i<n && visit[i]; ++i);
    15     if(i<n) return false;
    16     else
    17     {
    18         res = fac;
    19         return true;
    20     }
    21 }
    22 
    23 bool Traverse(int fac)
    24 {
    25     for(int i=0; i<(1<<n); ++i)
    26     {
    27         int subsum = 0;
    28         bool is_useful = true;
    29         for(int k=0; k<n; ++k)
    30         {
    31             if(i&(1<<k))
    32             {
    33                 if(visit[k] || subsum > fac)
    34                 {
    35                     is_useful = false;
    36                     break;
    37                 }
    38                 else subsum += sticks[k];
    39             }
    40         }
    41         if(is_useful && subsum == fac)
    42         {
    43             for(int k=0; k<n; ++k)
    44             {
    45                 if(i&(1<<k)) visit[k] = true;
    46             }
    47             if(judge(fac) || Traverse(fac)) return true;
    48             for(int k=0; k<n; ++k)
    49             {
    50                 if(i&(1<<k)) visit[k] = false;
    51             }
    52         }
    53     }
    54     return false;
    55 }
    56 
    57 int main()
    58 {
    59     #ifndef ONLINE_JUDGE
    60     freopen("F:\test\input.txt", "r", stdin);
    61     #endif // ONLINE_JUDGE
    62     while(cin>>n, n)
    63     {
    64         int curmax = 0;
    65         sumlen = 0;
    66         for(int i=0; i<n; ++i)
    67         {
    68             cin>>sticks[i];
    69             curmax = curmax > sticks[i] ? curmax :sticks[i];
    70             sumlen += sticks[i];
    71         }
    72         for(int fac = curmax; fac <= sumlen; ++fac)
    73         {
    74             if(sumlen%fac == 0)
    75             {
    76                 memset(visit, false, sizeof(visit));
    77                 if(Traverse(fac))
    78                 {
    79                     cout<<res<<endl;
    80                     break;
    81                 }
    82             }
    83         }
    84     }
    85 
    86     return 0;
    87 }

    自己后来又重新写了一遍,写的过程中感觉还是对回溯的理解还是不够深,回溯本是暴力的一种,所以这题也能看到一层一层搜索的路径,没有太多的技巧,都是根据题目的特性找规律,充分利用从而写出剪枝的条件,避免了超时,效率也更高。

    【AC代码】

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<string>
     4 #include<cstring>
     5 #include<algorithm>
     6 #define MAXN 1000
     7 
     8 using namespace std;
     9 
    10 int sticks[MAXN];
    11 bool visit[MAXN];
    12 int n, length, sum, sumlen;
    13 
    14 bool cmp(const int& a, const int& b)
    15 {
    16     return a>b;
    17 }
    18 
    19 bool Traverse(int num, int len, int cur)
    20 {
    21     if(num == sum) return true;
    22     for(int i=cur; i<n; ++i)
    23     {
    24         if(!visit[i] && !(i && !visit[i-1] && sticks[i] == sticks[i-1]))
    25         {
    26             if(len+sticks[i] == length)
    27             {
    28                 visit[i] = true;
    29                 if(Traverse(num+1, 0, 0)) return true;
    30                 visit[i] = false;
    31                 return false;
    32             }
    33             else if(len+sticks[i] < length)
    34             {
    35                 visit[i] = true;
    36                 if(Traverse(num, len+sticks[i], i+1)) return true;
    37                 visit[i] = false;
    38                 if(len == 0) return false;
    39             }
    40         }
    41     }
    42     return false;
    43 }
    44 
    45 
    46 int main()
    47 {
    48     #ifndef ONLINE_JUDGE
    49     freopen("F:\test\input.txt", "r", stdin);
    50     #endif // ONLINE_JUDGE
    51     while(cin>>n, n)
    52     {
    53         int curmax = 0;
    54         sumlen = 0;
    55         for(int i=0; i<n; ++i)
    56         {
    57             cin>>sticks[i];
    58             sumlen += sticks[i];
    59         }
    60         sort(sticks, sticks+n, cmp);
    61         for(int fac = sticks[0]; fac <= sumlen; ++fac)
    62         {
    63             if(sumlen%fac == 0)
    64             {
    65                 length = fac;
    66                 sum = sumlen/fac;
    67                 memset(visit, false, sizeof(visit));
    68                 if(Traverse(0,0,0)) break;
    69             }
    70         }
    71         cout<<length<<endl;
    72     }
    73 
    74     return 0;
    75 }
  • 相关阅读:
    解决com.xpand.. starter-canal 依赖引入问题
    缓存预热加入二级缓存
    缓存预热的实现
    ShardingSphere 中有哪些分布式主键实现方式?
    ShardingSphere 如何实现系统的扩展性
    如何系统剖析 ShardingSphere 的代码结构?
    SharingSphere的数据脱敏
    ShardingSphere的分布式事务
    Qt 事件过滤器原理(installEventFilter函数)
    Qt Event 以及 Event Filter 事件处理
  • 原文地址:https://www.cnblogs.com/liaoguifa/p/3183152.html
Copyright © 2011-2022 走看看