zoukankan      html  css  js  c++  java
  • 【状压DP】【UVA11795】 Mega Man's Mission

    传送门

    Description

      你要杀n个怪,每杀掉一个怪那个怪会掉落一种武器,这种武器可以杀死特定的怪。游戏初始你有一把武器,能杀死一些怪物。每次只能杀一只,求有多少种杀怪方法。

    Input

      多组数据,第一行是数组组数T,对于每组数据,有:

    • 第一行是怪物个数n
    • 第二行以0/1串的形式描述初始武器能杀死的怪物
    • 下面n行,第i行以0/1串的形式描述干掉第i只怪以后掉落武器能杀死的怪物

    Output

      对于每组数据,输出:

    • 杀怪的顺序数,形式为Case X: Y

    Sample Input

    3
    1
    1
    1
    2
    11
    01
    10
    3
    110
    011
    100
    000

    Sample Output

    Case 1: 1
    Case 2: 2
    Case 3: 3

    Hint

    n≤16

    Solution

    看看数据范围,大概是个状压DP。

    记录kldi为集合i在二进制意义下代表的怪物编号被干掉后掉落武器能干掉的怪物的集合。

    由于有一把初始武器,我们可以认为干掉任意集合的怪物都能干掉初始武器能干掉怪物的集合。

    设fi为干掉集合i在二进制意义下代表的怪物的顺序个数

    枚举该集合的每个元素,考虑该元素的补集被干掉后能不能干掉他,若能,则转移。

    转移用到加法原理,方程为fi+=f| j是i中的元素且kld[j^i]&j

    Code

    #include<cstdio>
    #include<cstring>
    #define rg register
    #define ci const int
    #define cl const long long int
    
    typedef long long int ll;
    
    inline void qr(int &x) {
        char ch=getchar(),lst=NULL;
        while(ch>'9'||ch<'0') lst=ch,ch=getchar();
        while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
        if (lst=='-') x=-x;
    }
    
    char buf[20];
    inline void write(int x,const char aft,const bool pt) {
        if(x<0) {putchar('-');x=-x;}
        int top=0;
        do {
            buf[++top]=x%10+'0';
            x/=10;
        } while(x);
        while(top) putchar(buf[top--]);
        if(pt) putchar(aft);
    }
    
    template <typename T>
    inline T mmax(const T &a,const T &b) {if(a>b) return a;return b;}
    template <typename T>
    inline T mmin(const T &a,const T &b) {if(a<b) return a;return b;}
    template <typename T>
    inline T mabs(const T &a) {if(a<0) return -a;return a;}
    
    template <typename T>
    inline void mswap(T &a,T &b) {T temp=a;a=b;b=temp;}
    
    const int maxn = 20;
    const int maxt = 131072;
    
    int t,cnt,n;
    ll frog[maxt];
    int gorf[maxn],kld[maxt];
    
    void clear();
    
    int main() {
        qr(t);
        while(t--) {
            clear();
            qr(n);
            for(rg int j=0;j<n;++j) {
                char ch=getchar();while((ch!='1') && (ch!='0')) ch=getchar();
                if(ch=='1') kld[0]|=(1<<j);
            }
            for(rg int i=0;i<n;++i) {
                for(rg int j=0;j<n;++j) {
                    char ch=getchar();while((ch!='1') && (ch!='0')) ch=getchar();
                    if(ch=='1') kld[1<<i]|=(1<<j);
                }
            }
            rg int upceil = (1<<n)-1;
            for(rg int i=0;i<=upceil;++i) {
                for(rg int j=0;j<n;++j) if((1<<j)&i) {
                    kld[i]|=kld[1<<j];
                }
                kld[i]|=kld[0];
            }
            frog[0]=1;
            for(rg int i=1;i<=upceil;++i) {
                for(rg int j=0;j<n;++j) if(i&(1<<j)){
                    if(kld[i^(1<<j)]&(1<<j)) frog[i]+=frog[i^(1<<j)];
                }
            }
            printf("Case %d: %lld
    ",++cnt,frog[upceil]);
        }
    }
    
    void clear() {
        n=0;
        memset(kld,0,sizeof kld);
        memset(frog,0,sizeof frog);
        memset(gorf,0,sizeof gorf);
    }

    Summary

    在状压DP进行转移的时候,不一定需要枚举子集进行转移,常用的另一种转移方式是枚举集合中元素进行转移。

  • 相关阅读:
    同源策略一
    执行命令firewallcmd zone=public addport=12345/tcp permanent后提示Error:INVALID_PORT
    ES6、ES7、ES8、ES9、ES10新特性一览 (个人整理,学习笔记)
    同源策略二
    国内加速访问Github的办法,超级简单
    Vue介绍篇
    Vue系列
    wp7中实现 INotifyPropertyChanged 是为了属性变更后的通知的代码笔记
    Sliverlight页面动态布局学习笔记
    windowphone中用WebBrowser加载google地图
  • 原文地址:https://www.cnblogs.com/yifusuyi/p/9452690.html
Copyright © 2011-2022 走看看