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

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 2006
using 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值