• UVa 11212 编辑书稿(dfs+IDA*)


     https://vjudge.net/problem/UVA-11212

    题意:给出n个自然段组成的文章,将他们排列成1,2...,n。每次只能剪切一段连续的自然段,粘贴时按照顺序粘贴。

    思路:状态空间的搜索问题。

            首先介绍一下IDA*,它属于DFS,在DFS遍历的时候,设定一个深度上限maxd,当前结点n的深度为g(n),乐观估价函数为h(n),则当g(n)+h(n)>maxd时应           该剪枝。这样的算法就是IDA*。

            在这道题目中,由于最多就9个数,所以最多只需要剪切8次肯定是可以完成升序排列的。所以最大深度可以从1开始一直到8,依次去寻找是否能成功。

            在这题中最重要的剪枝就是考虑后继不正确的数字个数h,可以证明每次剪切时h最多减少3,因此如果3*(maxd-d)<h,则可以直接剪枝。因为此时即使一直遍历到限定深         度maxd,也无法将h的个数减为0。另外也还有许多地方可以剪枝,下面的代码中我有仔细介绍。

     1 #include<iostream>
     2 #include<string>
     3 #include<cstring>
     4 using namespace std;
     5 
     6 int n;
     7 int a[12];
     8 
     9 bool goal() //判断是否已达到最终状态
    10 {
    11     for (int i = 0; i < n - 1; i++)
    12     {
    13         if (a[i]>a[i + 1]) return false;
    14     }
    15     return true;
    16 }
    17 
    18 int h()  //计算后继不正确的个数
    19 {
    20     int number = 0;
    21     for (int i = 0; i < n-1; i++)
    22     {
    23         if (a[i + 1] != a[i] + 1)
    24             number++;
    25     }
    26     if (a[n - 1] != n) number++;
    27     return number;
    28 }
    29 
    30 bool dfs(int d, int maxd)
    31 {
    32     if (3 * d + h()>3 * maxd)  return false; //剪枝
    33     if (goal())   return true;
    34     int pre[12];  //保存原来序列
    35     int cut[12];  //保存剪切后的序列
    36     for (int i = 0; i < n; i++)  //枚举,i为剪切起点,j为剪切终点
    37     {
    38         if (i == 0 || a[i]  != a[i - 1]+1) //剪枝,不破坏连续的数字片段
    39         {
    40             for (int j = i; j < n; j++)
    41             {
    42                 while (a[j + 1] == a[j] + 1)  j++; //剪枝,如果一个数字片段已经连续,则不要去破坏它
    43                 memcpy(pre, a, sizeof(a));  
    44                 int cnt = 0;
    45                 for (int k = 0; k < n; k++)  //保存剪切后的序号
    46                 {
    47                     if (k<i || k>j)
    48                         cut[cnt++] = a[k];
    49                 }
    50                 for (int k = 0; k <= cnt; k++)   //枚举,依次插入到第k个位置之前
    51                 {
    52                     int cnt2 = 0;
    53                     for (int t = 0; t < k; t++)  a[cnt2++] = cut[t];
    54                     for (int t = i; t <= j; t++) a[cnt2++] = pre[t];
    55                     for (int t = k; t < cnt; t++) a[cnt2++] = cut[t];
    56                     if (dfs(d + 1, maxd))      return true;  //继续深搜
    57                     memcpy(a, pre, sizeof(pre));  //如果失败,则恢复a[]的原来的数字片段
    58                 }
    59             }
    60         }
    61     }
    62     return false;
    63 }
    64 
    65 int solve()
    66 {
    67     if (goal())    return 0;
    68     for (int i = 1; i < 9; i++)   //最多只需要进行8次dfs即可获得最终状态
    69     {
    70         if (dfs(0, i))  return i;
    71     }
    72 }
    73 
    74 int main()
    75 {
    76     //freopen("D:\txt.txt", "r", stdin);
    77     int kase = 0;
    78     while (cin >> n && n)
    79     {
    80         memset(a, 0, sizeof(a));
    81         for (int i = 0; i < n; i++)
    82             cin >> a[i];
    83         int ans=solve();
    84         cout << "Case " << ++kase << ": " << ans << endl;
    85     }
    86 }

            

  • 相关阅读:
    课程开始的第一次作业
    第四次寒假作业——实现五种语言的选择
    关于改良报告与学习总结(Ⅰ)
    Vue路由守卫之路由独享守卫
    Vue路由守卫之组件内路由守卫
    Vue中如何插入m3u8格式视频,3分钟学会!
    Vue中如何使用less
    第一章 初识爬虫
    【JQuery】注册中实现图片预览
    【Python】多种方式实现生成验证码
  • 原文地址:https://www.cnblogs.com/zyb993963526/p/6344936.html
Copyright © 2020-2023  润新知