字母排序(关于拓扑排序的一些细节)

来源:互联网 发布:怎么设置ubuntu为中文 编辑:程序博客网 时间:2024/06/08 14:50

P1682

#include<map>#include<queue>#include<cmath>#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;#define a(i,j) a[i-96][j-96]//用宏定义简洁一些#define rd(i) rd[i-96]#define mark(i) mark[i-96]int n,m;char s1[25],s2[25],s[1005];int a[30][30],rd[30],mark[30];map<char,char>mp;void mycmp(char *s1,char *s2){    int len=min(strlen(s1),strlen(s2));//这里是min,不然会异常退出    for(int i=0;i<len;i++)    {        if(s1[i]!=s2[i])        {            //cout<<s1[i]<<"<"<<s2[i]<<endl;            if(a(s1[i],s2[i]))break;            //这里有一个区分:            /*            在邻接矩阵中是需要排除重复的,因为只计算了一条边而入度却增加了            相反在兄弟储存法里面就不需要,因为             */             a(s1[i],s2[i])=1;            mark(s1[i])=1;            mark(s2[i])=1;            rd(s2[i])++;            return;        }    }}void Init(){    scanf("%d%d",&n,&m);    scanf("%s",s1);    for(int i=2;i<=m;i++)    {        scanf("%s",s2);        mycmp(s1,s2);        strcpy(s1,s2);    }    /*for(int i=1;i<=26;i++)    {        cout<<mark[i]<<rd[i]<<endl;    }    cout<<endl;*/}vector<int>topo;bool toposort(){    queue<int>q;    for(int i=1;i<=26;i++)        if(!rd[i]&&mark[i])q.push(i);//邻接矩阵不能保证所有访问的节点都是已经定义的,因此必须加判断    while(!q.empty())    {        if(q.size()>1)return 0;        int i=q.front();q.pop();        topo.push_back(i);        for(int p=1;p<=26;p++)        {            if(!a[i][p])continue;            rd[p]--;            if(!rd[p])q.push(p);        }    }//  cout<<topo.size()<<endl;    if(topo.size()==n)        return 1;    return 0;}void out(){    for(int i=0;i<n;i++)    {        char c=topo[i]+96;        mp[c]=i+97;//这里的映射倒是很好用    }    scanf("%s",s);    int len=strlen(s);    for(int i=0;i<len;i++)        printf("%c",mp[s[i]]);}int main(){    Init();    if(toposort())    {        out();    }    else cout<<-1;    return 0;}

总结

关于拓扑排序

1、正常的BFS有三种返回关系,其中当q的元素大于1的时候不能直接返回多解,因为它有可能无解
2、DFS不好写,但是可以直接判断环

邻接矩阵

1、要标记节点是否已经被定义
2、要避免重复操作(本来是不影响的,就怕边数目没改更改了其他数据)

原创粉丝点击