SCAU 11162 Acmer入门之道

11162 Acmer入门之道

时间限制:1000MS 内存限制:65535K
提交次数:29 通过次数:9

题型: 编程题 语言: 无限制

Description

   方法向来是一个人取得成就的关键。于是每年都会有很多新生咨询老师,或者是师兄师姐学习方法,SCAU信软学院的莘莘学子们尤其踊跃。由于对专业缺乏了解,
很多新生都会为以下这些问题烦恼:比如是先学C++还是数据结构,又或者是先学Java还是Javascript。
   对于软件专业技术人员,大致分两种,一类是做应用,一类是做研发。做应用就是写一些手机电脑软件、网页等,要求对C++、Jsp等比较熟悉;研发就是为一些
应用软件的功能实现提供算法或者研究更高效的算法,要求对数据结构和算法的研究比较深刻,这类人才在各大公司都很抢手。
   ACM,毫无疑问,是培养研发人才的一个算法竞赛。作为通过了新生赛之初出茅庐的你,一定对如何搞好ACM很感兴趣吧O(∩_∩)O~….
   ACM对知识面的要求很高,需要看各种各样的书籍,什么具体数学,黑书(《算法导论》),白书(《算法竞赛入门经典》),算法设计,数据结构,C++等等。
为了帮助新生迅速入门,SCAU ACM校队的队员们决定给大家一些建议。
   Lrc:ACM的题目都是英文的,还是先学好英语再白书吧~
   Lys:目测具体数学是全英的,你不学好英文怎么看,呵呵…
   Xdp:白书比黑书更基础,新生还是先学白书再学黑书咯…
   Hq:据说《计算思维方式》能修炼内功,算法设计能修炼外功,我认为应该先修炼内功吧。
   Ly:算法设计作为大三的课本,比白书应该更适合入门吧(因为当年我只能看懂这本了~囧)。
   Wyh:算法归根到底是数学思维的结晶,先大概学一下具体数学再学算法设计更容易学精。
   Troy:算法里面很多是用到数据结构维护的,大家还是先学数据结构,打好基础再看算法设计呗。
   Yys:Acmer最终还是要工作的,在弄懂黑书的各种算法后,应该要看一遍C++学习面向对象的思想。
   Xym:C语言都学不好,怎么看数据结构呢?
   ………
   这些建议各种乱对不对?!
   Xym主席目测Ly的建议最没有建设性,于是命令Ly将这些科目按照建议排成一个特定的序列,好让师
弟师妹们参照这个顺序学习。对于某一条建议总会归纳出“要学B科目,应该先学A科目”,于是Xym主席
要求这个序列中B一定要排在A的后面。
   经过各种尝试,Ly终于千辛万苦把序列弄出来了:
   C语言 英语 具体数学 计算思维方式 数据结构 算法设计 白书 黑书 C++ 

   可是第二天开会,各位队员又很积极地提出来了上万条建议,这次,Ly凌乱了。作为SCAU ACM
校队未来的希望,你能拯救下Ly吗?(⊙o⊙)…

(出题人Ly)



输入格式

测试数据有多组。第一行输入一个整数T,表示测试数据的组数。
每组数据第一行两个整数n(n<=1000),m(m<=10000),分别代表建议涉及的科目数量和队员们提出的建议总数;
接下来n行,每行一个字符串Si,表示第i个科目的名称。所有字符串只有英文字母组成,长度均不超过15。
接下来m行,每行是一条建议,用两个字符串A,B表示,代表学科目B之前应该先学科目A。两个字符串之间用空格隔开。


输出格式

将所有科目按Xym主席的要求排成一个特定的序列,另外,如果A、B之间没有先后关系,科目名称字典序较小的将排在前面。然后按序列将科目名称逐一输出,
每个科目一行。
如果根据这些描述不能将所有科目排成所要求的序列,输出“No solution!”。


输入样例

2
9 9
English
Whitebook
Blackbook
Datastructure
Clanguage
Cplusplus
Modeofthinking
Algorithm
Math
English Whitebook
English Math
Whitebook Blackbook
Modeofthinking Algorithm
Algorithm Whitebook
Math Algorithm
Datastructure Algorithm
Blackbook Cplusplus
Clanguage Datastructure
3 3
Whitebook
Blackbook
Algorithm
Algorithm Whitebook
Whitebook Blackbook
Blackbook Algorithm


输出样例

Clanguage
Datastructure
English
Math
Modeofthinking
Algorithm
Whitebook
Blackbook
Cplusplus
No solution!
 
典型的拓扑排序问题:每次选择入度为0且字典序最小的点(用优先队列维护),删去这个点和这个点的所有出边。
 
AC代码:
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <map>
#include <cmath>
#include <vector>
#include <cstdlib>
using namespace std;

const int MAX=1005;
vector<int>v[MAX];  //用邻接表存图
int n,m,in[MAX],ans[MAX];
char s1[20],s2[20];
char sub[MAX][20];  //保存科目
bool vis[MAX];
priority_queue<int,vector<int>,greater<int> > q;
int cmp(const void*a,const void*b)
{
    return strcmp((char*)a,(char*)b);
}
int get_num(char* a)      //二分查找单词的序号
{
    int l=0,r=n;
    while(l<=r)
    {
        int mid=(l+r)/2;
        if(strcmp(sub[mid],a)==0)
            return mid;
        else if(strcmp(sub[mid],a)>0)
            r=mid-1;
        else
            l=mid+1;
    }
    return -1;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        for(int i=0; i<n; i++)
            v[i].clear();
        for(int i=0; i<n; i++)
        {
            scanf("%s",sub[i]);
        }
        qsort(sub,n,20,cmp);
        memset(in,0,sizeof(in));
        while(m--)
        {
            scanf("%s%s",s1,s2);
            int a=get_num(s1);
            int b=get_num(s2);
            v[a].push_back(b);
            in[b]++;
        }
        int cnt=0;
        memset(vis,false,sizeof(vis));
        for(int i=0; i<n; i++)
            if(!vis[i]&&in[i]==0)
                q.push(i);
        while(!q.empty())
        {
            int x=q.top();    //每次找字典序最小的
            ans[cnt++]=x;
            vis[x]=true;
            q.pop();
            for(int j=0; j<v[x].size(); j++)
            {
                in[v[x][j]]--;
                if(in[v[x][j]]==0&&!vis[v[x][j]])
                    q.push(v[x][j]);
            }
        }
        if(cnt<n)
            printf("No solution!\n");
        else
        {
            for(int i=0; i<cnt; i++)
                printf("%s\n",sub[ans[i]]);
        }
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值