poj1780

8 篇文章 0 订阅
涉及算法:非递归的dfs
题目大意: 求出一个长度为10^n+n-1的序列,其中包含了所有的n位数(一共10^n个数,从00000(n个0)~10^n-1)
题目分析:由于序列长度的限制,我们想要一个一个的写出0000(n个0)~10^n-1所有的数,是不可能的。由于10^n+n-1比我们所需要输出的数的个数只多n-1,所以基本上我们所求的序列每一位都要表示一个数,即第i个数的前n-1位是第i-1个数的后n-1位,而第一个数由于前面没有数字,所以第1个数就只能用一个n位数表示,这样序列的长度为n+10^n-1。我们在求第i个数的时候,要保证该数在前面i-1个数都没有出现过。

这个题目我一共用了三种方式来写,一种是最常见也最容易理解的递归的dfs,但是由于递归的次数太多,当n=4时就会产生StackOverFlowError。第二种是用stack来实现的非递归dfs,这个也不行,提交到判别系统中会MLE,最后只能参考别人的,不用stack的非递归,张见识了。

首先给出能够AC代码
package com.solo.dfs;

import java.util.Arrays;
import java.util.Scanner;

public class Main_1780_2
{

	static int maxn=1000010;
	static int vis[]=new int[maxn];
	static char ans[]=new char[maxn];
	static int nnow[]=new int[maxn];
	static int n;
	static int mod,end;
	public static void main(String[] args)
	{
		Scanner in=new Scanner(System.in);
		n=in.nextInt();
		while (n!=0)
		{
			Arrays.fill(vis, 0);
			Arrays.fill(ans, 0, n, '0');
			end=(int) Math.pow(10, n)+n-1;
			mod=(int) Math.pow(10, n-1);
			vis[0]=1;
			dfs();
			n=in.nextInt();
		}

	}
	
	public static void dfs()
	{
		int pos=n;int now=0;int i=0;
		nnow[pos-1]=0;
		while (pos<end)
		{
			now=nnow[pos-1]%mod;
			for(;i<10;i++)
			{
				if(vis[now*10+i]==0)
				{
					vis[now*10+i]=1;
					ans[pos]=(char)(i+'0');
					nnow[pos]=now*10+i;
					pos++;
					i=0;
					break;
				}
			}
			if(i==10)
			{
				pos--;
				vis[nnow[pos]]=0;
				i=nnow[pos]%10+1;
			}
		}
		for (int j = 0; j < end; j++)
		{
			System.out.print(ans[j]);
		}
		System.out.println();
		
	}

}

*********************************************************************************************************************************
没有AC的代码也贴出来给大家看看,虽然不能AC,但是可以用来看看递归dfs和非递归dfs的区别,非递归dfs的实现方式又有哪些不同
//递归的dfs
//递归次数太多会造成StackOverflowError
public class Main_1780
{
	static int maxn=1000000+10;
	static int ans[]=new int[maxn];
	static int vis[]=new int[maxn];
	static int end,mod;
	static int n;
	public static void main(String[] args)
	{
		Scanner in=new Scanner(System.in);
		n=in.nextInt();
		end=(int) Math.pow(10, n)+n-1;
		mod=(int) Math.pow(10, n-1);
		for (int i = 0; i < n; i++)
		{
			ans[i]=0;
		}
		vis[0]=1;
		dfs(n,0);
		for (int i = 0; i < end; i++)
		{
			System.out.print(ans[i]);
		}
	}
	
	public static boolean dfs(int pos,int now)//pos:序列的第i个位置,now:第pos位前的n-1位组成的n-1位数
	{
		if(pos==end)
		{
			return true;
		}
		
		for (int i = 0; i < 10; i++)
		{
			if(vis[now*10+i]==1) continue;
			vis[now*10+i]=1;
			ans[pos]=i;
			if(dfs(pos+1, (now*10+i)%mod))
			{
				return true;
			}
			vis[now*10+i]=0;
		}
		
		
		return false;
	}

}
//stack实现的非递归dfs
//MLE
public class Main_1780_3
{
	static int maxn=1000010;
	static int vis[]=new int[maxn];
	static int ans[]=new int[maxn];
	static int n;
	static int mod,end;
	public static void main(String[] args)
	{
		Scanner in=new Scanner(System.in);
		n=in.nextInt();
		while (n!=0)
		{
			Arrays.fill(vis, 0);
			mod=(int) Math.pow(10, n);
			end=(int) Math.pow(10, n)+n-1;
			Arrays.fill(ans, 0,n,0);
			dfs(new Node(0,n-1));
			n=in.nextInt();
		}
		
	}
	
	
	static class Node
	{
		Queue<Integer> adjNodes = new LinkedList<Integer>();//node
		int now;//node所对应的n位数字
		int pos;//node所放置的位置
		public Node(int now,int pos)
		{
			this.now=now;
			this.pos=pos;
			for(int i=0;i<=9;i++)
			{
				adjNodes.offer(i);
			}
			
		}
	}
	
	static void dfs(Node u)
	{
		int pos;
		Stack<Node> stack=new Stack<Node>();
		Node v;
		vis[u.now]=1;
		stack.push(u);
		while (!stack.isEmpty())
		{
			u=stack.peek();
			Integer i=u.adjNodes.poll();
			if(i==null)
			{
				vis[u.now]=0;
				stack.pop();
			}
			else {
				if (vis[(u.now*10+i)%mod]==0)
				{
					pos=u.pos+1;
					vis[(u.now*10+i)%mod]=1;
					ans[pos]=i;
					if(pos==end-1) break;
					stack.push(new Node((u.now*10+i)%mod, pos));
				}
			}
		}
		for (int i = 0; i <end ; i++)
		{
			System.out.print(ans[i]);
		}
		System.out.println();
		
	}
}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值