COCI 2010/2011 6th round--ABECEDA【拓扑排序】【字符串处理】

来源:互联网 发布:linux fm驱动 编辑:程序博客网 时间:2024/06/01 23:39

Description

Mirko has developed his own video game. The game has N levels and each successfully completed level
is worth a certain number of points, which add up to the player’s total score on an online rank list of all
players. Mirko has ordered his levels by difficulty from the easiest to the most difficult, but he has
made a mistake and made some difficult levels worth less points than some of the easier ones.
To overcome this problem, Mirko has decided to reduce the number of points for certain levels with
the goal of making the point sequence strictly increasing (so in the end easier levels are worth less
points than the difficult ones).
Help Mirko fix his video game in such a way that the total number of points reduced is minimal.
Final points have to be positive. You can assume that a solution exists for each test case.
题目大意就是给一些字符串,并且告诉你这些字符串是按照一套字母的大小顺序按照字典序排列的,只是你并不知道字母的大小顺序是什么样的,现在要让你求出出现过的所有字符的大小顺序,并且要求判断!(无解)、?(有多组解)。最多有100个字符串,没个字符串最多10位。

题解

大水题。直接按照题目给的东西建图(相同前缀,当前位不同,那么这一位上的两个字符就可以确定大小关系了),然后刷拓扑就可以了。但是还要判其他的东西,很烦。但是,我觉得在这个大小系统里,应该也不知道空字符的大小,所以刷的时候应该空字符也要当成字符来做,标程好像是按空字符默认最小来做的,所以数据有三个点是错的吧。

代码

#include<cstdio>#include<cstring>#include<algorithm>#define maxn 106#define maxe 2006using namespace std;inline char nc(){    static char buf[100000],*i=buf,*j=buf;    return i==j&&(j=(i=buf)+fread(buf,1,100000,stdin),i==j)?EOF:*i++;}inline int _read(){    char ch=nc();int sum=0;    while(!(ch>='0'&&ch<='9'))ch=nc();    while(ch>='0'&&ch<='9')sum=sum*10+ch-48,ch=nc();    return sum;}inline int _read_s(int*x){    char ch=nc();int len=0;    while(ch=='\n'||ch==' ')ch=nc();    while(ch!='\n'&&ch!=' '&&ch!=EOF)*(x++)=ch,ch=nc(),len++;    return len;}int n,nn,tot,L,hed,tal,dep[maxn],lnk[maxn],ent[maxn],que[maxn],son[maxe],nxt[maxe];bool vis[maxn],use[30];int a[maxn][16],ans[30];void add(int x,int y){    if(x<0||y<0)return;    nxt[++tot]=lnk[x];son[tot]=y;ent[y]++;lnk[x]=tot;}bool check(int x,int y,int k){    for(int i=1;i<=k;i++)if(a[x][i]!=a[y][i])return 0;    return 1;}void dfs(int x,int y,int p){    if(p>0&&x==y)ans[1]=-1;    if(ans[1]==-1)return;    vis[x]=0;    for(int j=lnk[x];j;j=nxt[j]) if(son[j]==y||vis[son[j]])dfs(son[j],y,1);}void check(){    for(int i=0;i<=26;i++){        memset(vis,1,sizeof(vis));        dfs(i,i,0);        if(ans[1]==-1)return;    }}void topo(){    hed=tal=0;    for(int i=0;i<=26;i++) if(use[i]&&!ent[i]){        if(i)ans[++ans[0]]=i+96;        que[++tal]=i;    }    while(hed!=tal)     for(int j=lnk[que[++hed]];j;j=nxt[j]) if(!(--ent[son[j]])){        que[++tal]=son[j];        if(son[j])ans[++ans[0]]=son[j]+96;        dep[son[j]]=dep[que[hed]]+1;     }    memset(vis,0,sizeof(vis));    for(int i=1;i<=26;i++) if(use[i]){        if(vis[dep[i]]){ans[1]=-2;return;}        vis[dep[i]]=1;    }}int main(){    freopen("abeceda.in","r",stdin);    freopen("abeceda.out","w",stdout);    n=_read();    memset(a,0,sizeof(a));    for(int i=1;i<=n;i++){        a[i][0]=_read_s(a[i]+1);L=max(L,a[i][0]);        for(int j=1;j<=a[i][0];j++)use[a[i][j]-96]=1;    }    use[0]=1;    for(int i=1;i<=26;i++) if(use[i])nn++;    for(int t=1;t<=L;t++)     for(int i=1;i<n;i++) if(check(i,i+1,t-1)&&a[i][t]!=a[i+1][t])         add(a[i][t]-96+96*(!a[i][t]),a[i+1][t]-96+96*(!a[i+1][t]));    memset(ans,0,sizeof(ans));    check();    if(ans[1]!=-1)topo();    if(ans[1]==-1)putchar('!');else    if(ans[1]==-2)putchar('?');else    for(int i=1;i<=ans[0];i++)putchar(ans[i]);    return 0;}