poj 1780 code(欧拉路)

/*
对于n为密码想要序列最短 那么 1234 2345 这两个一定挨着
就是说 前一个的后n-1位是后一个的前n-1位 假设n==3
我们用0-99作为点的编号建图 然后每个点连出去10条边
两个相邻点有n-1个是重复的 边的权值可用两个点计算
比如 12 23 权值为123  123 234 权值为1234
显然最后的序列是每个边记录一次 也就是跑欧拉路
对于记录下的边权 第一条输出前n-1为 上下的输出最后一位
这就是答案了 poj上没有special judge 要求字典序最小
这里建边时从9-0 就ok了
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 1000010
using namespace std;
int n,m,num,head[maxn],s[maxn],len;
int S[maxn],top,f[maxn],T[maxn];
struct node
{
    int u,v,t,pre;
}e[maxn*2];
void Clear()
{
    num=len=top=0;
    memset(head,-1,sizeof(head));
    memset(head,-1,sizeof(head));
    memset(f,0,sizeof(f));
}
void Add(int from,int to,int dis)
{
    e[num].v=to;
    e[num].t=dis;
    e[num].pre=head[from];
    head[from]=num++;
}
void Dfs(int x)
{
    S[++top]=x;T[top]=0;
    while(top)
      {
          int u=S[top],falg=0,ti=T[top];
          for(int i=head[u];i!=-1;i=e[i].pre)
            {
                int v=e[i].v;
                if(f[e[i].t])continue;
                falg=1;f[e[i].t]=1;
                S[++top]=v;T[top]=e[i].t;
                break;
          }
        if(!falg)s[++len]=ti,top--;
      }
}
int main()
{
    while(scanf("%d",&n)&&n)
      {
          Clear();
          if(n==1){puts("0123456789");continue;}
          int t=1,r=1;
          for(int i=1;i<n;i++)t*=10,r*=10;r/=10;
          for(int i=0;i<t;i++)
            for(int j=9;j>=0;j--)
              Add(i,i%r*10+j,i*10+j);
          Dfs(0);
          for(int i=1;i<=n-2;i++)printf("0");
          printf("%d",s[len]/10);
          for(int i=len-1;i>=1;i--)printf("%d",s[i]%10);
          printf("\n");
      }
}

 

posted @ 2016-08-25 21:39  一入OI深似海  阅读(150)  评论(0编辑  收藏  举报