ZOJ 1346 Comparing Your Heroes (状态压缩dp 精简)*

Comparing Your Heroes


Time Limit: 10 Seconds      Memory Limit: 32768 KB


Nowadays many students wouldn't attend classes in university, instead, they stay in dormitory playing Electronic games on computers. One of the most popular games among the boys is KOF (the King Of Fighters), a kind of action game presented by SNK corporation. This series of games becomes so successful that SNK has even created comics and story for it. Although in the story IORI and KYO are the definitely two strongest heroes, it would not affect players' true affection of other characters. Actually, every player has his own favorite heroes.

As a fanatical fan of the KOF game, you're going to help the other players to find out the ranking of their favorite heroes. Players would only provide information of comparisons between the heroes. This sometimes can lead to confusion: maybe not only one ranking satisfies the comparisons. So at first you'd like to find out the number of the rankings that satisfy a specific player's comparisons.


Input

The input consists of several test cases. Each test case begins with a positive integer N on a line, indicating the number of the comparisons. The following N lines are the comparisons between the heroes. Each one is a line containing 2 names of the heroes separated by a space, means the player prefer the first hero to the second. The name of the hero is a sequence of at most 10 upper case letters. No two comparisons would be same, and you can always assure one's favorite heroes would not exceed 16.


Output

For each test case, print out the number of the rankings that satisfy the comparisons on a single line. If no such ranking exists, just print out 0.


Sample Input

4
IORI KYO
MARY SHERMIE
KYO ANDY
SHERMIE ANDY
3
IORI KYO
KYO CLARK
CLARK IORI


Sample Output

6
0
#include<iostream>
#include<algorithm>
#include<string>
#include<map>//int dx[4]={0,0,-1,1};int dy[4]={-1,1,0,0};
#include<set>//int gcd(int a,int b){return b?gcd(b,a%b):a;}
#include<vector>
#include<cmath>
#include<stack>
#include<string.h>
#include<stdlib.h>
#include<cstdio>
#define mod 1e9+7
#define ll long long
#define maxn 16
#define ms memset
using namespace std;

const int  INF=(1<<30);
int dp[1<<maxn],pre[maxn];
int n,m;
char name[maxn][maxn];
char str[2][maxn];
/*
题目大意:给定n对人物的名字,
代表前一个比后一个更厉害,
计数这种偏序关系可以产生的排名数量是多少。

与拓扑排序相关的状态压缩。
首先通过二进制表示的状态的累加来表示一个点的
前缀,即前提条件。
那么状态压缩及其dp的状态转移如何实现呢?
首先对于一种子偏序状态,如果新增一个点且
新的点的前缀都在子状态中出现过,
那么新状态的dp计数要加上子状态的计数。
如何让这样的过程推进不产生重复计数或是漏记呢?
记住在新状态s|(1<<i)中,这个状态永远在s后面出现,
跟数论里面的筛法比较像,我也在体会。。
*/
void input()
{
    int u,v;  n=0;
    memset(pre,0,sizeof(pre));
    for(int i=0;i<m;i++)
    {
        scanf("%s%s",str[0],str[1]);
        for(u=0;u<n;u++)
        {
            if(strcmp(name[u],str[0])==0)
                break;
        }
        if(u==n) strcpy(name[n++],str[0]);

        for(v=0;v<n;v++)
        {
            if(strcmp(name[v],str[1])==0)
                break;
        }
        if(v==n) strcpy(name[n++],str[1]);

        pre[v] |= (1<<u);
    }
}

void solve()
{
    memset(dp,0,sizeof(dp));
    dp[0]=1;
    for(int s=0;s<(1<<n);s++) if(dp[s]!=0){
        for(int i=0;i<n;i++)
        {
            if( ( (s&pre[i])==pre[i] ) && !( s&(1<<i) ) )
                dp[s | (1<<i)] += dp[s];
         }
    }
    printf("%d\n",dp[(1<<n)-1]);
}

int main()
{
    while(scanf("%d",&m) != EOF)
    {
        input();
        solve();
    }
    return 0;
}

 


Source: Zhejiang University Local Contest 2002

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值