ZOJ 1346 Comparing Your Heroes - 状压dp

9 篇文章 0 订阅

题目描述

题目大意:

某人要对拳皇的人物做一个排序。输入一个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();
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值