拓扑排序

字母排序问题
总时间限制: 10000ms 单个测试点时间限制: 1000ms 内存限制: 65536kB
描述
G教授是xoi的负责人,有一天他竟然发现自己的计算机染上了一种不常见的病毒。这种病毒的名字叫做ALPHABETVIRUS,当它发作时,会将字母用其它的字母代替,但不会将顺序交换。
病毒将计算机中的所有文档都作了相对应的改变。很幸运,G教授的计算机上有一个字典,而我们都知道字典单词是按字母顺序排列的,当然,这个字典也被病毒改变了。因此,利用字典原来的有序性,找到自动替换字母的规律,再用以恢复其它文档。由于XOI不能缺少G教授的文件,所以文档必须恢复。但是由于G教授有其它更重要的工作要完成,所以他希望你可以帮助他恢复文档,使得XOI的工作可以继续。
G教授会提供感染病毒后的字典和他希望能帮助恢复的字典足。
输入
输入文件的第一行是两个整数A(A<=26)和K(K<=50000),A表示需要恢复的字母的个数,K表示字典里与这几个字母有关系的单词个数,它们之间用一个空格隔开。接下来的K行按原来的字典顺序给出这K个单词。第K+1行是要你恢复的字母组,字母为小写字母。
输出
输出文件应该将字母组输出,如果不可将字母区分,则输出0。
样例输入
5 6
cebdbac
cac
ecd
dca
aba
bac
cedab
样例输出
abcde


#include<bits/stdc++.h>
using namespace std;
int mp[27][27];
int mmp[27];
int cor[27];
int top=1;
int main()
{
int A,K;
scanf("%d%d",&A,&K);
string S1,S2,S3;
if(K<=1)
{
cout<<"0";
return 0;     
}
cin>>S1;
int tot=K-1;
int n=K;
    K--;
while(K--)
{
cin>>S2;
int l1=S1.length();
int l2=S2.length();
for(int i=0;i<min(l1,l2);i++)
{
int flag=0;
if(S1[i]!=S2[i])
{
mp[S1[i]-'a'+1][S2[i]-'a'+1]=1;
flag=1;
break;
}
}
S1=S2;
}
/*for(int i=1;i<=A;i++)
{
for(int j=1;j<=A;j++)
   cout<<mp[i][j]<<"^";
   cout<<endl;
}*/

for(int i=1;i<=A;i++)
for(int j=1;j<=A;j++)
        mmp[j]+=mp[i][j];
    while(tot--)
{
int flag=0,ans;
for(int i=1;i<=A;i++)
{
if(flag==2)
{
cout<<"0";
return 0;
}
if(mmp[i]==0)
   {
    ans=i;
    mmp[i]=-1;
    flag++;
    cor[i]=top;
    top++;
   }

}
for(int j=1;j<=A;j++)
{
mmp[j]-=mp[ans][j];
}
//for(int i=1;i<=A;i++)
//printf("%d ",mmp[i]);
//printf("\n");
if(flag==0)
{
cout<<"0";
return 0;
}
}
    /*for(int i=1;i<=top;i++)
cout<<char(cor[i]+'a'-1);*/
cin>>S3;
int l3=S3.length();
for(int i=0;i<l3;i++)
{
cout<<char(cor[S3[i]-'a'+1]+'a'-1);
}
}


、车站分级(level.cpp/c/pas)——拓扑排序

描述

一条单向的铁路线上,依次有编号为1,2,...,n的n个火车站。每个火车站都有一个级别,最低为1级。现有若干趟车次在这条线路上行驶,每一趟都满足如下要求:如果这趟车次停靠了火车站x,则始发站、终点站之间所有级别大于等于火车站x的都必须停靠。

(注意:起始站和终点站自然也算作事先已知需要停靠的站点)

例如,下表是5趟车次的运行情况。其中,前4趟车次均满足要求,而第5趟车次由于停靠了3号火车站(2级)却未停靠途经的6号火车站(亦为2级)而不满足要求。


现有m趟车次的运行情况(全部满足要求),试推算这n个火车站至少分为几个不同的

级别。

【输入】

输入文件为level.in。

第一行包含2个正整数n,m,用一个空格隔开。

第i+1行(1≤i≤m)中,首先是一个正整数si(2≤si≤n),表示第i趟车次有si个停

靠站;接下来有si个正整数,表示所有停靠站的编号,从小到大排列。每两个数之间用一个

空格隔开。输入保证所有的车次都满足要求。

【输出】

输出文件为level.out。

输出只有一行,包含一个正整数,即n个火车站最少划分的级别数。

【输入输出样例】

level.in

level.out

92

41356

3356

2

93

41356

3356

3159

3

【数据范围】

对于20%的数据,1≤n,m≤10;

对于50%的数据,1≤n,m≤100;

对于100%的数据,1≤n,m≤1000。

#include<bits/stdc++.h>

using namespace std;

#define N 1001

struct edge

{

     intv,next,to;

}mem[N*N];

int n,m,size,MAX;

int a[N],head[N],in[N],q[N],ans[N];

bool mapp[N][N],v[N];

void add(int from,int to)

{

     size++;

     mem[size].to=to;

     mem[size].next=head[from];

     head[from]=size;

}

void topsort()

{

     int tot=0;

     int tmp=1;

     for(inti=1;i<=n;i++)

          if(in[i]==0){//计算入度为零的点

              tot++;

              q[tot]=i;

          }

     while(tot<n){

          intkobe=0;//Kobe记录的是这一次有几个新进入队列的点  没错就是Kobe Bryant

          for(inti=tmp;i<=tot;i++){//小优化 上一波处理完毕的这一次不管了 

              intnow=q[i];

              for(inte=head[now];e;e=mem[e].next){

                   in[mem[e].to]--;

                   if(in[mem[e].to]==0){

                        kobe++;

                        q[tot+kobe]=mem[e].to;//起点加上kobe为序号

                        ans[mem[e].to]=ans[now]+1;//转移

                   }

              }

          }

          tmp=tot+1;//指针改变

          tot=tot+kobe;

     }

}

int main()

{

     freopen("level.in","r",stdin);

     freopen("level.ans","w",stdout);

     scanf("%d%d",&n,&m);

     for(inti=1;i<=m;i++){

          int si;

          memset(v,0,sizeof(v));

          scanf("%d",&si);

          for(intj=1;j<=si;j++){

              scanf("%d",&a[j]);

              v[a[j]]=1;//记录是否停过

          }

          for(intj=a[1];j<=a[si];j++){//枚举从起点到终点的点

              if(v[j])continue;//停过跳过

              for(intk=1;k<=si;k++) //枚举停过的点

              if(mapp[a[k]][j]==0)add(a[k],j),mapp[a[k]][j]=1,in[j]++;

          }

     }

     topsort();

     for(inti=1;i<=n;i++)MAX=max(MAX,ans[i]);

     printf("%d",MAX+1);//别忘了ans没有赋初值 最大的等级也是一个 要都加1

}

 

 

 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Antique Comedians of Malidinesia would like to play a new discovered comedy of Aristofanes. Putting it on a stage should be a big surprise for the audience so all the preparations must be kept absolutely secret. The ACM director suspects one of his competitors of reading his correspondece. To prevent other companies from revealing his secret, he decided to use a substitution cipher in all the letters mentioning the new play. Substitution cipher is defined by a substitution table assigning each character of the substitution alphabet another character of the same alphabet. The assignment is a bijection (to each character exactly one character is assigned -- not neccessary different). The director is afraid of disclosing the substitution table and therefore he changes it frequently. After each change he chooses a few words from a dictionary by random, encrypts them and sends them together with an encrypted message. The plain (i.e. non-encrypted) words are sent by a secure channel, not by mail. The recipient of the message can then compare plain and encrypted words and create a new substitution table. Unfortunately, one of the ACM cipher specialists have found that this system is sometimes insecure. Some messages can be decrypted by the rival company even without knowing the plain words. The reason is that when the director chooses the words from the dictionary and encrypts them, he never changes their order (the words in the dictionary are lexicographically sorted). String a1a2 ... ap is lexicografically smaller than b1b2 ... bq if there exists an integer i, i <= p, i <= q, such that aj=bj for each j, 1 <= j < i and ai < bi. The director is interested in which of his messages could be read by the rival company. You are to write a program to determine that. Input Output Sample Input 2 5 6 cebdbac cac ecd dca aba bac cedab 4 4 cca cad aac bca bdac Sample Output abcde Message cannot be decrypted.

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值