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

P1682

#include
#include
#include
#include
#include
#include
#include
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;iif(s1[i]!=s2[i])
        {
            //cout<
            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<
}
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<
    if(topo.size()==n)
        return 1;
    return 0;
}
void out()
{
    for(int i=0;ichar c=topo[i]+96;
        mp[c]=i+97;//这里的映射倒是很好用
    }
    scanf("%s",s);
    int len=strlen(s);
    for(int i=0;iprintf("%c",mp[s[i]]);
}
int main()
{
    Init();
    if(toposort())
    {
        out();
    }
    else cout<<-1;
    return 0;
}

总结

关于拓扑排序

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

邻接矩阵

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

你可能感兴趣的:(图论)