CoderForce 180D-Name (构造+回溯)

题目大意:给两个字符串s,t,用s中的字符重新组合构造出按字典序最小的但比t大的新字符串。

题目分析:先统计s中各个字母出现的次数,然后从t的左端向右端依次构造出新串的每一位上的字母。这个过程我是用回溯实现的,因为只需进行到字典序比t大就可以立即停止,所以实际上花不了多少时间。

代码如下:

# include<iostream>
# include<string>
# include<algorithm>
# include<cstdio>
# include<vector>
# include<cstring>
using namespace std;

int n,m;
int vis[5005];
string p,q;
int cnt[26];
int ans[5005];

int isBigger()
{
    for(int i=1;i<=ans[0]&&i-1<m;++i){
        if(ans[i]<q[i-1]-‘a‘) return -1;
        if(ans[i]>q[i-1]-‘a‘) return 1;
    }
    if(ans[0]==m) return 0;
    else if(ans[0]>m) return 1;
    else return -1;
}

bool dfs(int i)
{
    int k=isBigger();
    if(k>0) return true;
    if(i>=m){
        if(k>0) return true;
        else if(k==0) return n>m;
        else if(k<0) return false;
    }
    for(char c=q[i];c<=‘z‘;++c){
        if(cnt[c-‘a‘]==0) continue;
        --cnt[c-‘a‘];
        ans[++ans[0]]=c-‘a‘;
        if(dfs(i+1)) return true;
        --ans[0];
        ++cnt[c-‘a‘];
    }
    return false;
}

int main()
{
    //while(cin>>p>>q){
        cin>>p>>q;
        n=p.size();
        m=q.size();

        memset(cnt,0,sizeof(cnt));
        for(int i=0;i<n;++i)
            ++cnt[p[i]-‘a‘];

        ans[0]=0;
        if(!dfs(0))
            printf("-1\n");
        else{
            for(int i=1;i<=ans[0];++i)
                cout<<(char)(ans[i]+‘a‘);
            for(int i=0;i<26;++i)
                for(int j=0;j<cnt[i];++j)
                    cout<<(char)(i+‘a‘);
            cout<<endl;
        }
    //}
    return 0;
}

  

时间: 2024-10-09 14:25:39

CoderForce 180D-Name (构造+回溯)的相关文章

hdu 5355 Cake(构造+回溯)

题意: 给出一个蛋糕,切成1~n大小的n块,问能否在不继续切割的情况下拼凑出m等份. 解析: 首先可以求出这些蛋糕的总和n?(n+1)/2,如果总和sum%m != 0那么就不肯能被平分成m份,那么输出"NO". 接下来计算平均数avg=sum/m,如果平均数avg < n的话,蛋糕是不可能用完的,同样也输出"NO". 剩下的情况蛋糕是一定能拼成"YES"的,那么可以将这些蛋糕以2*m为单位一组一组的分配,每个人拿当前这组的最大和最小,次大

[转]五大常用算法:分治、动态规划、贪心、回溯和分支界定

Referred from http://blog.csdn.net/yapian8/article/details/28240973 分治算法 一.基本概念 在计算机科学中,分治法是一种很重要的算法.字面上的解释是“分而治之”,就是把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题……直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并.这个技巧是很多高效算法的基础,如排序算法(快速排序,归并排序),傅立叶变换(快速傅立叶变换)…… 任何一个可以用计算机求

回溯法

递归回溯 由于回溯法是对解空间的深度优先搜索,因此在一般情况下可用递归函数来实现回溯法如下: t表示递归深度,即当前扩展节点在解空间树的深度. n用来控制递归深度.当t>n时表示算法搜索到叶节点. void backtrack( int t ) { if ( t>n ) output(x); else for( int i=f(n,t); i<=g(n,t); i++ ) { x[t]=h(i); if ( constraint(t)&&bound(t) ) backtr

Codeforces 453C Little Pony and Summer Sun Celebration(构造)

题目链接:Codeforces 453 Little Pony and Summer Sun Celebration 题目大意:n个节点,m条边,然后m行给定边,最后一行表示每个节点需要进过的次数为奇数次还是偶数次. 解题思路:构造,任意从一个奇数点开始(统一森林的处理),然后每次向下遍历没有经过的节点,并且回溯,每次回溯都要判断一下刚才走过的点满不满足条件,不满足的话就再走一次.最后对于根节点,最后一次回溯要不要走根据当前走过的次数决定. #include <cstdio> #include

构造数独

编程之美有一道关于深度搜索和回溯应用的题目--构造数独: 数独的棋盘是由九九八十一个小方格组成的.玩家在每个小格子中,分别天上1至9的任意一个数字,让整个棋盘每一行,每一列,以及每一个3*3的小矩阵中的数字都不重复. 作者给两种解法: 解法一: 下面的GenerateValidMatrix()函数用经典的深度优先搜索来生成一个可行解.从(0,0)开始,对没有处理过的格子,调用GetValidValueList(coCurrent)来获得当前格子可能的取值选择,并从中取一个为当前格子的取值,接着搜

第1章 游戏之乐——构造数独

构造数独 1. 问题 构造一个9*9的方格矩阵,玩家要在每个方格中,分别填上1至9的任意一个数字,让整个棋盘每一列.每一行以及每一个3*3的小矩阵中的数字都不重复. 2. 求解 用转置的方法生成数独数组,代码如下: 1 package chapter1youxizhileShuDu; 2 3 import java.util.Random; 4 5 /** 6 * 用置换法生成数独矩阵 7 * @author DELL 8 * 9 */ 10 public class ShuDu { 11 pr

ACM:回溯法,子集生成

(一)增量构造法 #include <iostream> #include <algorithm> using namespace std; const int MAXN = 1000; int A[MAXN], n; void print_subset(int n, int *A, int cur) { for(int i = 0; i < cur; ++i) cout << A[i] << " "; cout <<

分治法、动态规划、回溯法、分支界限法、贪心算法

转:http://blog.csdn.net/lcj_cjfykx/article/details/41691787 分治算法一.基本概念 在计算机科学中,分治法是一种很重要的算法.字面上的解释是“分而治之”,就是把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题……直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并.这个技巧是很多高效算法的基础,如排序算法(快速排序,归并排序),傅立叶变换(快速傅立叶变换)…… 任何一个可以用计算机求解的问题所需的计算时

构造可配置词法语法分析器生成器(上)

本文为笔者原创,转载请注明出处 http://blog.csdn.net/xinghongduo 前言 源程序在被编译为目标程序需要经过如下6个过程:词法分析,语法分析,语义分析,中间代码生成,代码优化,目标代码生成.词法分析和语法分析是编译过程的初始阶段,是编译器的重要组成部分,早期相关理论和工具缺乏的环境下,编写词法语法分析器是很繁琐的事情.上世纪70年代,贝尔实验室的M. E. Lesk,E. Schmidt和Stephen C. Johnson分别为Unix系统编写了词法分析器生成器Le