zoukankan      html  css  js  c++  java
  • HDU5816 Hearthstone(状压DP)

    题目

    Source

    http://acm.hdu.edu.cn/showproblem.php?pid=5816

    Description

    Hearthstone is an online collectible card game from Blizzard Entertainment. Strategies and luck are the most important factors in this game. When you suffer a desperate situation and your only hope depends on the top of the card deck, and you draw the only card to solve this dilemma. We call this "Shen Chou Gou" in Chinese.

    Now you are asked to calculate the probability to become a "Shen Chou Gou" to kill your enemy in this turn. To simplify this problem, we assume that there are only two kinds of cards, and you don't need to consider the cost of the cards.
    -A-Card: If the card deck contains less than two cards, draw all the cards from the card deck; otherwise, draw two cards from the top of the card deck.
    -B-Card: Deal X damage to your enemy.

    Note that different B-Cards may have different X values.
    At the beginning, you have no cards in your hands. Your enemy has P Hit Points (HP). The card deck has N A-Cards and M B-Cards. The card deck has been shuffled randomly. At the beginning of your turn, you draw a card from the top of the card deck. You can use all the cards in your hands until you run out of it. Your task is to calculate the probability that you can win in this turn, i.e., can deal at least P damage to your enemy.

    Input

    The first line is the number of test cases T (T<=10).
    Then come three positive integers P (P<=1000), N and M (N+M<=20), representing the enemy’s HP, the number of A-Cards and the number of B-Cards in the card deck, respectively. Next line come M integers representing X (0<X<=1000) values for the B-Cards.

    Output

    For each test case, output the probability as a reduced fraction (i.e., the greatest common divisor of the numerator and denominator is 1). If the answer is zero (one), you should output 0/1 (1/1) instead.

    Sample Input

    2
    3 1 2
    1 2
    3 5 10
    1 1 1 1 1 1 1 1 1 1

    Sample Output

    1/3
    46/273

     

    分析

    题目大概说有两种卡牌,使用A牌能从牌堆摸两张牌,使用B牌能对对方造成xi点伤害。在你的回合,你从牌堆摸一张牌,问能对对方造成p点及以上伤害的概率。

    要求的其实就是能造成p点以上伤害的牌堆排列数/牌堆全排列数

    全排列而且总数为20,这种就该想到尝试用状压DP。。

    • dp[S]表示已经摸的牌的集合为S的可行排列方案数

    对于一个状态S,我们能从这个集合中已经摸的牌知道还能摸几张,即A的数目 * 2 - A的数目 - B的数目 + 一开始能摸的一张牌

    考虑状态的转移,我是用我为人人实现的:从小到大枚举状态S,判断S是否合法,即S的方案数不为0且还能摸牌,然后通过S去更新S+i(i∉S)状态的值。另外如果S能造成的伤害已经大于等于p了,那就没必要去更新它能转移到的状态,因为还剩下的牌直接求全排列计算其贡献,这样也能避免重复计算。

    最后就循环遍历各个合法的状态累加贡献,这个贡献就是dp值 * 还没摸的牌的全排列数。这样就求出能造成p点以上伤害的牌堆排列数,再和全排列数用GCD搞搞输出答案即可。

    代码

    #include<cstdio>
    #include<cstring>
    using namespace std;
    
    long long fact[22]={1};
    
    long long gcd(long long a,long long b){
    	if(b==0) return a;
    	return gcd(b,a%b);
    }
    
    int p,n,m,N,x[22];
    long long d[1<<20];
    
    int main(){
    	for(int i=1; i<22; ++i) fact[i]=fact[i-1]*i;
    	int t;
    	scanf("%d",&t);
    	while(t--){
    		scanf("%d%d%d",&p,&n,&m);
    		N=n+m;
    		for(int i=n; i<N; ++i){
    			scanf("%d",&x[i]);
    		}
    		
    		memset(d,0,sizeof(d));
    		d[0]=1;
    		for(int s=0; s<(1<<N); ++s){
    			if(d[s]==0) continue;
    			
    			int A=0,B=0,damage=0;
    			for(int i=n; i<N; ++i){
    				if(s>>i&1){
    					damage+=x[i];
    					++B;
    				}
    			}
    			if(damage>=p) continue;
    			for(int i=0; i<n; ++i){
    				if(s>>i&1) ++A;
    			}
    			
    			if(A-B+1<=0) continue;
    			
    			for(int i=0; i<N; ++i){
    				if(s>>i&1) continue;
    				d[s^(1<<i)]+=d[s];
    			}
    		}
    		
    		long long xx=0,yy=fact[N];
    		for(int s=0; s<(1<<N); ++s){
    			if(d[s]==0) continue;
    			int A=0,B=0,damage=0;
    			for(int i=n; i<N; ++i){
    				if(s>>i&1){
    					damage+=x[i];
    					++B;
    				}
    			}
    			for(int i=0; i<n; ++i){
    				if(s>>i&1) ++A;
    			}
    			if(damage>=p){
    				xx+=d[s]*fact[N-A-B];
    			}
    		}
    		long long g=gcd(xx,yy);
    		printf("%I64d/%I64d
    ",xx/g,yy/g);
    	}
    	return 0;
    }
    
  • 相关阅读:
    获得数据控件事件索引并获取其中值总结
    关于dropdwonlist无法获得值问题
    通过反射,将datatable转换为List集合(反射读取实体类的属性,并赋值),通过接口来实现MySql和MsSql数据的切换(二层反射),静态构造函数,抽象类和接口的区别
    Reflection反射,Assembly程序集,Type类型类,AssemblyQualifiedName程序集的限定名,DataTable和IList接口互相转化
    memcache实战之三 :客户端 enyim.com Memcached Client 的安装与调试以及实例,2012年下载地址
    memcache实战之一 :服务器端软件 memcached1.2.6win32bin 的 详细安装和调试
    一些.net开发需要额外熟悉的东西
    memcache实战之二 :客户端 Memcached Providers 1.2 for .net 2.0 的安装与调试以及实例,curr_items 和 total_items的区别
    MySQL ('root'@'%') does not exist的问题
    asp.net 结合 memcache 进行分布式缓存的开发,结合mysql数据库
  • 原文地址:https://www.cnblogs.com/WABoss/p/5754721.html
Copyright © 2011-2022 走看看