hdu 4850 字符串构造---欧拉回路构造序列 递归+非递归实现

http://acm.hdu.edu.cn/showproblem.php?pid=4850

题意:构造长度为n的字符序列,使得>=4的子串只出现一次

其实最长只能构造出来26^4+4-1= 456979 的序列,大于该数的都是不可能的。构造方法,就是那种欧拉回路的序列,此题DFS会爆栈,手动扩展栈也可以AC......

递归形式的开始WA了,没有细调就换非递归了,后来又想了想,虽然自己电脑上运行不了,但是先把长度按小的来,然后调试代码,然后在扩大,AC了,当时错在MOD,递归的MOD应该是26^4,而不是26^4+1,因为控制在0~(26^4-1)范围内,就是456976个数

所以要变成非递归,我其实不太理解非递归的,然后参考自己以前做过的也是不太理解的这个代码http://blog.csdn.net/u011026968/article/details/38151303

然后AC

非递归版  46ms AC

//#pragma comment(linker, "/STACK:102400000,102400000")
//#pragma comment(linker, "/STACK:102400000,102400000")
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <iostream>
#include <iomanip>
#include <cmath>
#include <map>
#include <set>
#include <queue>
using namespace std;

#define ls(rt) rt*2
#define rs(rt) rt*2+1
#define ll long long
#define ull unsigned long long
#define rep(i,s,e) for(int i=s;i<e;i++)
#define repe(i,s,e) for(int i=s;i<=e;i++)
#define CL(a,b) memset(a,b,sizeof(a))
#define IN(s) freopen(s,"r",stdin)
#define OUT(s) freopen(s,"w",stdout)
const ll ll_INF = ((ull)(-1))>>1;
const double EPS = 1e-8;
const int INF = 100000000;
const int MAXN = 101;
const int S = 500000;
const int SIZE = 26;
const int LEN = 456976+3;
//const int MOD = 456976;
const int MOD =17576;

char str[LEN+10];
char li[LEN*SIZE+10];
int sta[LEN*SIZE+10];

/*int dfs(int cnt, int s)
{
    //printf("cnt=%d %d\n",cnt,s);
    if(cnt == LEN)return 1;
    for(int i=0;i<SIZE;i++)
    {
        if(!vis[(s*SIZE+i)%MOD])///
        {
            vis[(s*SIZE+i)%MOD]=1;
            str[cnt]=i;
            if(dfs(cnt+1, (s*SIZE+i)%MOD))return 1;
            //vis[(s<<1)+i]=0;
        }
    }
    return 0;
}*/
int tp,ans;
void sea(int v)
{
    while(li[v]<SIZE)
    {
        int w=v*SIZE+li[v];
        li[v]++;
        sta[tp++]=w;
        v=w%MOD;
    }
}
void solve()
{
    CL(str,0);
    CL(li,0);
    tp=0;
    int v;
    sea(0);
    str[0]='a';
    ans=1;
    while(tp)
    {
        v=sta[--tp];
        str[ans++]=v%SIZE+'a';
        v/=SIZE;
        sea(v);
    }
}

int main()
{
    //OUT("hdu4850.txt");
    solve();
    int n;
    while(~scanf("%d",&n))
    {
        if(n>LEN)puts("Impossible");
        else
        {
            if(n<=4)
            {
                for(int i=0;i<n;i++)
                    putchar('a');
            }
            else
            {
                for(int i=1;i<4;i++)putchar('a');
                int tt=ans;
                n-=3;
                while(tt>ans-n)putchar(str[--tt]);
            }
            putchar('\n');
        }
    }
    return 0;
}

递归版 93ms AC

#pragma comment(linker, "/STACK:102400000,102400000")
//#pragma comment(linker, "/STACK:102400000,102400000")
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <iostream>
#include <iomanip>
#include <cmath>
#include <map>
#include <set>
#include <queue>
using namespace std;

#define ls(rt) rt*2
#define rs(rt) rt*2+1
#define ll long long
#define ull unsigned long long
#define rep(i,s,e) for(int i=s;i<e;i++)
#define repe(i,s,e) for(int i=s;i<=e;i++)
#define CL(a,b) memset(a,b,sizeof(a))
#define IN(s) freopen(s,"r",stdin)
#define OUT(s) freopen(s,"w",stdout)
const ll ll_INF = ((ull)(-1))>>1;
const double EPS = 1e-8;
const int INF = 100000000;
const int MAXN = 101;
const int S = 500000;
const int SIZE = 26;
const int LEN = 456976+3;
const int MOD = 456976;

int str[LEN+10];
int vis[LEN+10];

int dfs(int cnt, int s)
{
    //printf("cnt=%d %d\n",cnt,s);
    if(cnt == LEN)return 1;
    for(int i=0;i<SIZE;i++)
    {
        if(!vis[(s*SIZE+i)%MOD])///
        {
            vis[(s*SIZE+i)%MOD]=1;
            str[cnt]=i;
            if(dfs(cnt+1, (s*SIZE+i)%MOD))return 1;
        }
    }
    return 0;
}

void init()
{
    CL(str,0);
    CL(vis,0);
    vis[0]=1;
    dfs(4,0);
}

int main()
{
    //OUT("hdu4850.txt");
    init();
    int n;
    while(~scanf("%d",&n))
    {
        if(n>LEN)puts("Impossible");
        else
        {
            for(int i=0;i<n;i++)
                putchar(str[i]+'a');
            putchar('\n');
        }
    }
    return 0;
}
时间: 2024-12-23 01:15:07

hdu 4850 字符串构造---欧拉回路构造序列 递归+非递归实现的相关文章

二叉树总结—建树和4种遍历方式(递归&amp;&amp;非递归)

今天总结一下二叉树,要考离散了,求不挂!二叉树最重要的就是 建立.4种遍历方式,简单应用,如何判断两颗二叉树是否相似 二叉树分为 :1.完全二叉树  2.满二叉树 结构性质: 1).满二叉树 高度为h ,节点数则为 2^h - 1,且叶子节点全在最下层,且叶子节点数为2^(n-1)个{n代表二叉树层数,也叫深度} 2).n个节点的 完全二叉树 深度为 int(log2n)(以2为底n的对数)+ 1: 3).非空二叉树 叶子节点个数==双分支节点数+1 4).非空二叉树 某节点编号 n  若有左孩

快速排序递归非递归队列堆栈实现

递归实现 #include<iostream> using namespace std; template <class T> void QuickSort(T A[],int left,int right) { if(left<right) { int i=left; int j=right+1; do { do i++;while(A[i]<A[left]); do j--;while(A[j]>A[left]); if(i<j) Swap(A[i],A

【算法拾遗】二分查找递归非递归实现

转载请注明出处:http://blog.csdn.net/ns_code/article/details/33747953 本篇博文没太多要说的,二分查找很简单,也是常见常考的查找算法,以下是递归非递归的实现. 非递归实现: /* 非递归实现,返回对应的序号 */ int BinarySearch(int *arr,int len,int key) { if(arr==NULL || len<1) return -1; int low = 0; int high = len-1; while(l

hdu 4850 Wow! Such String! 构造 或 欧拉路径并改写成非递归版本

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4850 跟这道题也算是苦大仇深了... 题意:构造一个由26个小写字母组成的.无长度为4的重复子串的字符串(要求出能构造出的最大长度) 符合要求的长度为4的字符串有4^26个 容易猜最大长度是:4^26+3 = 456979 比赛的时候想法是要让各个字母出现得尽量“均匀” 用了一个cnt数组记录26个字母出现的次数 每次都选择出现次数最小的.不与前面重复的字母加上去 然而稍微写得有点歪,最后构造出了长

二叉树——前序遍历、中序遍历、后序遍历、层序遍历详解(递归非递归)

前言 前面介绍了二叉排序树的构造和基本方法的实现.但是排序遍历也是比较重要的一环.所以笔者将前中后序.和层序遍历梳理一遍. 了解树的遍历,需要具有的只是储备有队列,递归,和栈.这里笔者都有进行过详细介绍,可以关注笔者数据结构与算法专栏.持续分享,共同学习. 层序遍历 层序遍历.听名字也知道是按层遍历.我们知道一个节点有左右节点.而每一层一层的遍历都和左右节点有着很大的关系.也就是我们选用的数据结构不能一股脑的往一个方向钻,而左右应该均衡考虑.这样我们就选用队列来实现. 对于队列,现进先出.从根节

格雷码那点事——递归非递归实现

简介 在一组数的编码中,若任意两个相邻的代码只有一位二进制数不同,则称这种编码为格雷码(Gray Code),另外由于最大数与最小数之间也仅一位数不同,即“首尾相连”,因此又称循环码或反射码.在数字系统中,常要求代码按一定顺序变化.例如,按自然数递增计数,若采用8421码,则数0111变到1000时四位均要变化,而在实际电路中,4位的变化不可能绝对同时发生,则计数中可能出现短暂的其它代码(1100.1111等).在特定情况下可能导致电路状态错误或输入错误.使用格雷码可以避免这种错误.格雷码有多种

查找 —— 二分查找[递归+非递归]

二分查找 二分查找是对一组有序序列进行查找.根据要查找的k和序列中间元素比较,动态的移动查找范围.以对折的方式缩小查找范围. 递归方式: def binarySearch(A,left,right,k): if left<= right: mid =(left+right)//2 if A[mid] == k: return mid if A[mid]>k: return binarySearch(A,left,mid-1,k) #此处要返回函数运行结果而不是仅仅调用函数 else: retu

排序算法 归并算法(递归+非递归)

部分理论和图来自:http://www.cnblogs.com/jingmoxukong/p/4308823.html  (侵删) 归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用. 将已有序的子序列合并,得到完全有序的序列:即先使每个子序列有序,再使子序列段间有序.若将两个有序表合并成一个有序表,称为二路归并. 归并排序的基本思想 将待排序序列R[0...n-1]看成是n个长度为1的有序序列,将相邻的有序表成对归并,

归并排序 - 递归非递归实现java

1.归并排序思想: 以2路归并为例,一个有n个记录的序列可以看作n个长度为1的有序子序列,将其两两合并成n/2(向上取整)个长度为2或1的有序序列,当有奇数个记录时为1,重复归并,直到得到一个长度为n的有序序列. 2.归并排序的复杂度: 递归:时间复杂度O(nlongn),空间复杂度O(n+longn) 非递归:时间复杂度O(nlongn),空间复杂度O(n) 所以用到归并排序,还是优先考虑非递归吧.  3.递归实现 1 public void mergeSort1(int[] data){ 2