uva140_dfs(回溯)最优性剪枝

题解:

1.原书中已经说明,如果两个节点的带宽 >= 最小带宽,无论如何也不可能比原解更优,应该剪掉。

2.注意此题读入的时候一定要按 字典序 存储,这样计算出的最小值才是符合要求的

3.注意strtok的用法


#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
//////////////////////
#include<iostream>
#include<algorithm>
#include<string>
#include <iterator>
#include<sstream>
#include<functional>
#include<numeric>
///////////////////////
#include<vector>
#include<map>
#include <stack>
#include<queue>
#include<set>
#include <bitset>
#include <list>
using namespace std;
#define lch(x)  ((x) << 1)
#define rch(x) ((x)<<1|1)
#define dad(x) ((x)>>1)
#define lowbit(x) ((x)&(-x))
typedef  long long int LL;
const int INF = ~0U>>1;
const double eps = 1e-6;
const long double PI = acos(0.0) * 2.0;
const int N = 10+200;
map<char,int> id;

int mi ,n;
char in[N];
int v[N],ans[N],tmp[N];
bool vis[N],G[N][N];

bool read();
void dfs(int cur , int x);
int ID(char x){return id[x];}

int main()
{
    //ios::sync_with_stdio(false);
#ifdef ONLINE_JUDGE
#else
    freopen("in.txt", "r", stdin);
    //freopen("out3.txt", "w", stdout);
#endif
    while(read())
    {
        mi = n; //带宽最大为n
        dfs(0,0);   //dfs(当前位置,上一次算的带宽)
        for(int  i = 0 ; i < n ; i++)       printf("%c ",v[ ans[i] ]+‘A‘);
        printf("-> %d\n",mi);
    }
    return 0;
}

bool read()
{
    gets(in);
    if(in[0]==‘#‘)  return 0;
    char * p,*s=in;
    memset(vis,0,sizeof(vis));
    int l = strlen(in);
    for(int i = 0 ; i< l ; i++) if(isalpha(in[i])) vis[in[i]-‘A‘]=1;  //字典序查找点
    n = 0;          //按字典序把点映射,并收集起来
    for(int i = 0 ; i < 27 ; i++)    if(vis[i])    v[ id[i+‘A‘]=n++ ] = i;

    memset(G,0,sizeof(G));
    while(p = strtok(s,";"))//分割字符串
    {
        for(int i = 2 ; p[i]!=‘\0‘ ; i++)   //转化成邻接矩阵储存,方便查询
            G[ ID(p[0])][ ID(p[i]) ] = G[ ID(p[i])][ ID(p[0])] = 1;
        s = NULL;
    }

    memset(vis,0,sizeof(vis));
    return 1;
}

void dfs(int cur , int x)
{
    if(cur == n)//能运行到这一步的值必定比前一个小
    {                  //更新它
        mi = x;
        memcpy(ans,tmp,sizeof(tmp));
        return ;
    }

    for(int  i = 0 ; i < n ; i++)//回溯生成排列
    {
        if(!vis[i])
        {
            vis[i] = 1;
            tmp[cur] = i;
            int dk = 0;
            for(int j = 0 ; j < cur ; j++)
            {
                if(G[ i ][ tmp[j] ])
                {
                    dk = cur - j;
                    break;
                }
            }
            dk = max(x,dk);
            if(dk < mi)    dfs(cur+1,dk);   //如果某个节点的带宽比当前最小带宽大,剪掉它
            vis[i] = 0;
        }
    }
}

版权声明:本文为博主原创文章,允许非商业性转载,转载必须注名作者(CSDN tt2767)与本博客链接:http://blog.csdn.net/tt2767。

时间: 2024-11-08 17:01:03

uva140_dfs(回溯)最优性剪枝的相关文章

Sticks(回溯和剪枝和关于局部变量的问题)

做这道题要哭了= = 之前把所有的变量都定义成全局变量,结果提交时老是RT,找不到错.后来改成局部变量就ac了= =. Sticks(3.4.2) Time Limit:1000MS    Memory Limit:10000KB    64bit IO Format:%I64d & %I64u SubmitStatus Description George took sticks of the same length and cut them randomly until all parts

HDU 4848-Wow! Such Conquering!(DFS+最优性剪枝)

Wow! Such Conquering! Time Limit: 15000/8000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 846    Accepted Submission(s): 255 Problem Description There are n Doge Planets in the Doge Space. The conqueror of Doge S

【BZOJ2342】【Shoi2011】双倍回文 Manacher+枚举+最优性剪枝

题解:Manacher处理出回文半径,然后知道一个回文串后就可以知道两边的回文中心,然后O(1)check是否合法,即判断两边中心的回文半径. 这里需要枚举每一个位置的回文半径,因为比如这个 18 abbbaabbbaccddddcc ccddddcc就不是双倍回文,但是它中间有个dddd是双倍回文,如果每个回文只check最长的是不是双倍回文,就会WA在这里. Manacher算法:http://blog.csdn.net/vmurder/article/details/42119417 所以

uva10400 - Game Show Math(回溯+剪枝)

题目:uva10400 - Game Show Math(回溯+剪枝) 题目大意:给出N个数,并且给出一个目标数值,要求用上面的数字(全部),并且顺序不能乱,然后用+-*/这些操作,问最终能不能得到目标数值.这里要注意给出的数会在[-32000,32000]之间, 并且要用除法的时候,只有在能整除的时候才能用.并且中间计算结果不能超过[-32000,32000]范围.如果超过这个操作不能做. 解题思路:回溯加剪枝,将每一层计算的结果都保存下来,如果在同一层发现值出现过,并且之前计算发现这样往后是

【转】POJ-2362-Square:简单 DFS+剪枝

思路: 首先将输入的各边长累加求和 即四边形周长sum, 后除4 即边长side,这样 通过DFS 搜索这些sticks能否组合成4根长度均为side 进而确定yes no. 在此 就涉及到搜索顺序了-最优性剪枝: 不难理解 先搜索的小棒子 越长,组合构成side的方式就越少,搜索到结果的时间就越短. SO从最长的棒子开始进行DFS. // num表示已确认组合构成 的side的数目 即所求正方形的边数 // len表示所求正方形边长度 s表示搜索起点 #include<iostream> #

剪枝算法--优化搜索(转载)

转载于:http://princetonboy.ycool.com/post.2805302.html [摘要]本文讨论了搜索算法中“剪枝”这一常见的优化技巧. 首先由回溯法解决迷宫问题展开论述,介绍了什么是剪枝; 而后分析剪枝的三个原则正确.准确.高效,并分别就剪枝的两种思路:可行性剪枝及最优性剪枝,结合例题作进一步的阐述; 最后对剪枝优化方法进行了一些总结. [关键字]搜索.优化.剪枝.时间复杂度 引论 在竞赛中,我们有时会碰到一些题目,它们既不能通过建立数学模型解决,又没有现成算法可以套用

剪枝算法(算法优化)

一:剪枝策略的寻找的方法 1)微观方法:从问题本身出发,发现剪枝条件 2)宏观方法:从整体出发,发现剪枝条件. 3)注意提高效率,这是关键,最重要的. 总之,剪枝策略,属于算法优化范畴:通常应用在DFS 和 BFS 搜索算法中:剪枝策略就是寻找过滤条件,提前减少不必要的搜索路径. 二:剪枝算法(算法优化) 1.简介 在搜索算法中优化中,剪枝,就是通过某种判断,避免一些不必要的遍历过程,形象的说,就是剪去了搜索树中的某些"枝条",故称剪枝.应用剪枝优化的核心问题是设计剪枝判断方法,即确定

深搜的剪枝技巧

众所周知,搜索是个好东西,他能在很多时候(就是你不会正解打暴力的时候)派上用场. 然而搜索的时间复杂度实在是太高了,大多数都是指数级别的,这让人很是头疼 那么我来总结一下对搜索进行优化的技巧:剪枝 什么是剪枝 我们知道,搜索的进程可以看做遍历一棵搜索树的过程.而所谓的剪枝,就是通过某种判断,避免一些不必要的遍历过程. 形象的来说,就是剪掉搜索树上的一些枝条来达到减少遍历次数,缩短时间复杂度的效果 剪枝的原则 1.正确性 废话,你剪枝都把正确的答案剪了你还搜个啥呢? 2.准确性 尽可能多的剪去不需

一本通例题埃及分数—题解&amp;&amp;深搜的剪枝技巧总结

一.简述: 众所周知,深搜(深度优先搜索)的时间复杂度在不加任何优化的情况下是非常慢的,一般都是指数级别的时间复杂度,在题目严格的时间限制下难以通过.所以大多数搜索算法都需要优化.形象地看,搜索的优化过程就像将搜索树上没用的枝条剪下来,因此搜索的优化过程又叫剪枝.剪枝的实质就是通过判断决定是否要沿当前枝条走下去. 二.搜索的剪枝必需遵循三个原则: 1.正确性(不能把正解排除,要不然搜什么呢?)2.准确性(尽可能把不能通向正解的枝条剪去)3.高效性(因为在每个枝条上都要进行一次判断,如果判断的复杂