ZOJ 1346 Comparing Your Heroes - 状压dp

题目描述

题目大意:

某人要对拳皇的人物做一个排序。输入一个N,接下来N行每行两个字符串A B,表示A比B厉害。要求一共有多少种不同的拓扑排序方法。若不能完成排序输出0。

分析:

dp[S] (S表示点是否被取出的状态):得到S状态的方案数
dp[S|(1<< k)]+=dp[S] => 在S状态下,入度为0的点记为k
初始状态:dp[0]=1
目标状态:dp[(1<< n)-1]

#include<cstdio>
#include<cstring>
#define MAXN 20
#define MAXL 10

struct node{
    int v;
    node *next;
}edge[MAXN*200+10],*adj[MAXN+10],*ecnt=&edge[0];
int m,n,dp[(1<<MAXN)+10],in[MAXN+10];
char st[MAXN*16+10][MAXL+10];

void Init(){
    memset(adj,0,sizeof adj);
    ecnt=&edge[0];
    memset(st,0,sizeof st);
    n=0;
}
int Get_id(char *s){
    for(int i=1;i<=n;i++)
        if(!strcmp(st[i],s))
            return i;
    strcpy(st[++n],s);
    return n;
}
void addedge(int u,int v)
{
    node *p=++ecnt;
    p->v=v;
    p->next=adj[u];
    adj[u]=p;
}
void read()
{
    char s[MAXL+10],t[MAXL+10];
    for(int i=1;i<=m;i++){
        scanf("%s%s",s,t);
        int p=Get_id(s),q=Get_id(t);
        addedge(p,q);
    }
}
void check(int S)
{
    memset(in,0,sizeof in);
    for(int i=1;i<=n;i++){
        if(S&(1<<(i-1)))
            continue;
        for(node *p=adj[i];p;p=p->next)
            if(!(S&(1<<(p->v-1))))
                in[p->v]++;
    }
}
void DP()
{
    int S=(1<<n)-1;
    memset(dp,0,sizeof dp);
    dp[0]=1;
    for(int i=0;i<=S;i++){
        check(i);
        for(int j=1;j<=n;j++)
            if(!(i&(1<<(j-1)))&&!in[j])
                dp[i|(1<<(j-1))]+=dp[i];
    }
    printf("%d\n",dp[S]);
}
int main()
{
    while(scanf("%d",&m)==1){
        Init();
        read();
        DP();
    }
}
posted @ 2016-03-20 11:13  KatarinaYuan  阅读(153)  评论(0编辑  收藏  举报