HDU 3559 Frost Chain

Frost Chain

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others)
Total Submission(s): 495    Accepted Submission(s): 214


Problem Description
In the unimaginable popular DotA game, the hero Lich has a wonderful skill: Frost Chain, release a jumping breath of frost that jumps N times against enemy units.



Today iSea play the role of Lich, at first he randomly chooses an enemy hero to release the skill, then the frost jumps for N times. Each time, it make a damage of one HP unit on this hero (including the first time), then bounces to another hero (can’t be himself) if their distance is no more than D and this hero is alive of course, also randomly. Here random means equal probability.

Now we know there are always only five enemy heroes, and also their coordinates and HP value. iSea wonders the death probability of each hero. One hero is dead if its HP is equal to or less than zero.

 

Input
There are several test cases in the input.

Each test case begin with two integers N and D (1 <= N <= 25, 1 <= D <= 10000).
The following line contains ten integers, indicating the coordinates of the five opponents, and -10000 ≤ x, y ≤ 10000.
Then five integers follows, indicating the HP (1 <= HP <= 5) of five opponents.

The input terminates by end of file marker.

 

Output
For each test case, output five floating numbers, indicating the death probability of each hero, as the given order, rounded to three fractional digits, and separated by a single blank.
 

Sample Input
  
  
3 100 0 1 0 2 0 3 0 4 0 5 1 1 1 1 1 3 1 0 1 0 2 0 3 0 4 0 5 1 1 1 1 1
 

Sample Output
  
  
0.800 0.800 0.800 0.800 0.800 0.500 0.800 0.800 0.800 0.500

题意:在DOTA中有个英雄叫LICH,他的大招能弹跳n(n<=25)次(不能弹跳同一个人),作用范围为d,每次命中目标能够扣除对方1点的HP,对方有5个英雄,给出每个英雄的坐标以及HP(HP<=5),每次命中目标后都会自动寻找d范围内的英雄,直到弹跳n次后或者没有其他存活的英雄。求大招结束后每个英雄死亡的概率


题解:

由于英雄总数为5个,HP最多为5,枚举所有状态的状态数也只有6*6*6*6*6=46656种,为了运算方便,我取8*8*8*8*8=262144种状态(只是内存花销大了,由于采用8进制能够使用位运算,所以实际运行速度不会变慢),我们可以采用一个dp数组记录一下每种状态的概率

记dp[i][j][k]为在第j次弹跳,跳到i身上,当前所有英雄状态为k的概率(当然你如果不嫌麻烦也可以开一个7维数组),采用BFS,遍历每一次跳跃能够得到的状态,然后将结果加起来,就能得到答案了


以下为AC代码


#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
int n,status;
bool gap[7][7];//记录两点之间是否能够到达
double dp[7][30][1<<15];
/*
dp[i][j][k]第j次造成伤害,停留在i上,状态为k的概率
*/
double D;
int QK[7*30*(1<<15)],QS[7*30*(1<<15)],QL[7*30*(1<<15)];
/*
模拟队列用,QK用于存储弹跳次数,QS存储状态,QL存储停留在哪个人身上
*/
bool vis[7][30][1<<15];
const int M[5]={28672,3584,448,56,7};
/*
这些数写为2进制为111000000000,000111000000,000000111000,000000000111000,000000000000111,与这些数取与(&)可以判断对应位置的英雄是否存活
*/
const int De[5]={4096,512,64,8,1};
/*
对应英雄的血量减一
*/
double ans[5];


struct coor
{
    double x;
    double y;
}hero[5];


double dis(coor a,coor b)
{
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}


int num(int s,int h)//用于计算在状态s时,除了h以外存活的英雄的数量
{
    int cnt=0;
    for(int i=0;i<5;i++)
        if(gap[h][i]&&(s&M[i]))
            cnt++;
    return cnt;
}
void bfs()
{
    int head=0,tail=1;
    QK[0]=0;
    QS[0]=status;
    QL[0]=6;
    dp[6][0][status]=1.0;
    while(head<tail)
    {
        int k=QK[head],s=QS[head],last=QL[head];
        head++;
        if(k==n+1)
            continue;
        if(vis[last][k][s])
            continue;
        vis[last][k][s]=true;
        for(int i=0;i<5;i++)
        {
            int nh=num(s,last);
            if(nh&&(s&M[i])&&gap[i][last])
            {
                double t=dp[last][k][s]/(nh*1.0);
                dp[i][k+1][s-De[i]]+=t;
                if(!((s-De[i])&M[i]))
                    ans[i]+=t;
                if(vis[i][k+1][s-De[i]])
                    continue;
                QK[tail]=k+1;
                QS[tail]=s-De[i];
                QL[tail]=i;
                tail++;
            }
        }
    }
    for(int i=0;i<tail;i++)
    {
        int k=QK[i],s=QS[i],last=QL[i];
        vis[last][k][s]=false;
        dp[last][k][s]=false;
    }
    /*
        注意这里两个case之间不能用memset,不然会TLE,原因是你BFS的过程中有许多状态没有用到
    */
}


int main()
{
    memset(dp,0,sizeof dp);
    memset(vis,0,sizeof vis);
    while(scanf("%d%lf",&n,&D)!=EOF)
    {
        memset(gap,0,sizeof gap);
        for(int i=0;i<5;i++)
        {
            double x,y;
            scanf("%lf%lf",&x,&y);
            hero[i].x=x;
            hero[i].y=y;
        }
        for(int i=0;i<5;i++)
            for(int j=0;j<5;j++)
            {
                if(i==j)
                    continue;
                if(dis(hero[i],hero[j])<=D)
                    gap[i][j]=true;
            }
        status=0;
        for(int i=0;i<5;i++)
        {
            status<<=3;
            int hp;
            scanf("%d",&hp);
            status+=hp;
        }
        for(int i=0;i<=6;i++)//假设一个结点6能够连通所有的结点
            gap[i][6]=gap[6][i]=true;
        for(int i=0;i<5;i++)
            dp[i][0][status]=1.0;
        memset(ans,0,sizeof ans);
        bfs();
        for(int i=0;i<4;i++)
            printf("%.3f ",ans[i]);
        printf("%.3f\n",ans[4]);
    }
    return 0;
}     

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。、可私 6信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 、可私信6博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 、可私信6博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值