POJ 1780 - Code 非递归..输出欧拉回路边路径..

                题意:

                         给一个进制k(1~5)..输出一种方案使得0~10^k-1排成一排(相邻的每k位都为不同的数,所以长度严格为10^k+k-1),,,并且字典序最小..

                题解:

                        想了好久..写了好久..看了别人的代码..才完全明白...解释几个地方:

                        1、点: 点是0~10^(k-1)的数...为什么不能直接用第一位和最后一位..比如做那种首位相连的字符串欧拉回路时.一个字符串不时只要头字符和末字符两个信息就可以了吗...因为两个数字相接不是最后一个和第一个相同就行了...必须是前面数的后k-1位和后一个数的前k-1位相同...一定要注意...所以对于此类问题做点可以总结为.用会相互重叠的部分做为点....

                        2、边: 边就是代表了0~10^k的数

                        3、欧拉回路: 因为这么构造任意点的入度=出度..所以存在欧拉回路

                        4、RE..因为递归过多..所以要手动模拟递归....

                        5、由于我的邻接表习惯用插头法构造...所以做边时从9~0添加就可以保证在找路径时顺着找就能找到最小字典序解...

Program:

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<time.h>
#include<map>
#include<algorithm>
#define ll long long
#define eps 1e-5
#define oo 1000000007
#define pi acos(-1.0)
#define MAXN 1000500
#define MAXM 1000500
using namespace std;
struct node
{
       int y,id,next;
}line[MAXM],temp[MAXM]; 
int Lnum,_next[MAXN],ans[MAXM],num,S[MAXN],Snum; 
bool used[MAXM];
void addline(int x,int y,int id)
{
       line[++Lnum].next=_next[x],_next[x]=Lnum,line[Lnum].y=y,line[Lnum].id=id;
}
void dfs(int x)
{
       int i,k; 
       Snum=0,S[++Snum]=x;
       while (Snum)
       {
             x=S[Snum--]; 
             for (k=_next[x];k;k=line[k].next) 
                if (!used[line[k].id])
                {
                     used[line[k].id]=true; 
                     S[++Snum]=x,S[++Snum]=line[k].y;
                     goto A;
                }
             ans[++num]=x; 
             A: ;
       }
}
int main()
{             
       int n,k,i,x,y;  
       while (~scanf("%d",&k) && k)
       {
               if (k==1) 
               {
                       printf("0123456789\n");
                       continue;
               }
               n=1;
               for (i=1;i<k;i++) n*=10; 
               Lnum=0,memset(_next,0,sizeof(_next));
               for (i=0;i<n;i++)  
               {
                       x=i%(n/10);
                       for (y=9;y>=0;y--) addline(i,x*10+y,i*10+y);
               }
               memset(used,false,sizeof(used)),num=0;
               dfs(0);
               for (i=1;i<k-1;i++) ans[++num]=0;
               for (i=num;i>=1;i--) printf("%d",ans[i]%10);
               printf("\n");
       }
       return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值