[遗传算法]冰与火之歌 (转自 a2520123)

[题目描述]
在著名游戏“冰与火之歌”中英雄们亲自参战了!英雄一开始有HPH点生命值与MPH点魔法值,英雄们能够使用不同的技能,你的英雄会三种技能:雷霆之怒、混沌转移和天使之心。
英雄要打一群怪兽,每只怪兽一开始有HPM点生命值,这一群怪兽一开始有NM只,它们的总生命值就有HPM×NM点,随着战斗的进行,怪兽群的总生命值减少。假设当前怪兽群有H点总生命值,那么还存活的怪兽个数为H/HPM取上整。
战斗在一个一维的包含N+1个格子的战场上进行,格子从0开始编号,你的英雄一直在0号格子不动,怪兽们一开始在N号格子并且可以移动,怪兽们一回合最多移动V个格子。
战斗是回合制的,你的英雄是先手,英雄与怪兽轮换进行,怪兽的策略非常简单,它们先往英雄的方向移动min(V,P-1)格,P为它们在回合一开始所在的格子的编号,如果怪兽们在移动之后到达了1号格子,那么它们就会攻击你的英雄,如果有K只怪兽进行攻击,你的英雄就会扣掉K点生命值,如果你的英雄的生命值变为了非正数,那么这场战斗就失败了。
在你的英雄的回合,他必须要施展三种技能中的一种,三个技能的效果如下:
雷霆之怒:减少怪物群LP点生命值,P为怪物们所在的格子的编号。
混沌转移:把怪物群传送到任何一个格子(不能为0号)。
天使之心:你的英雄恢复dH点生命值,但是不能超过初始生命值。
施展任何一种技能都需要消耗1点魔法值,当怪物群的生命值降为0时,你的英雄取得胜利。
给出一种初始局面,请你判断你的英雄是否有获得胜利的策略,如果有,请输出任何一种胜利的决策方案。
[数据范围]
1 ≤N ≤ 10, 2 ≤ HPH ≤ 100, 1 ≤ MPH ≤ 50, 1 ≤ HPM ≤10, 1 ≤ NM ≤ 10, 1 ≤ V ≤ N, 1 ≤ dH < HPH,1 ≤ Li ≤ 10

Orz qw!!!想我写记忆化搜索,真是给跪。

以下是 qw 原创的题解。

[题解]

        这道题正解应该是搜索或者dp,不过我考场上由于上一道题打了模拟退火,所以就用遗传算法做了一下(虽然这两个东西似乎没什么联系).第一次用遗传算法,各种WA,不过主要是因为题目意思没有理解清楚,遗传算法的部分其实不难.

        我是以英雄死前能对怪兽造成的最大伤害来评价一个个体的优劣的.产生下一代的方法是:最优的10个个体直接进入下一轮遗传,再选10对个体随机交配,交配的个体分别将自己一半的基因给子代,子代在其基因片段中随出若干个片段产生变异,这里我借鉴模拟退火的方法,随机的次数越多,选择的变异片段越少.实际的评测效果很好,有很大的几率能够AC,我最少也随出85分.另外,初始时的个体应该可以贪心搞出一些优秀的个体,这样的话算法的正确性会进一步提升.(由于评测机器的差异,可能要减少循环次数)

        在排序的过程中,我用的是选择排序.为了避免数组的交换,我直接定义了两个指针来加速.

Code:

program heroes;  
type  
        int=longint;arr=array[1..50]of char;point=^arr;  
        arr2=array[1..50]of int;p2=^arr2;  
const skill:array[0..2]of char=('L','T','H');  
var  
        i,j,k,m,n,ii,t:int;ok:boolean=false;  
        h_h,m_h,n_m,h_m,v_m,dh,h_tot_m:int;  
        lp,next:array[1..20]of int;  
        f:array[1..20]of arr;  
        g:array[1..20]of arr2;  
        p:array[1..20]of point;  
        q:array[1..20]of p2;  
        harm:array[1..20]of int;  
        aa:array[1..120000]of int;  
        po1:point;po2:p2;  
  
function min(x,y:int):int;  
begin  
        if x<y then exit(x)  
                else exit(y);  
end;  
  
function get(p:point;q:p2):int;var i,j,h,m:int;//计算个体适应度  
begin  
        get:=0;h:=h_h;m:=n;  
        for i:=1 to m_h do begin  
                if p^[i]='L'then inc(get,lp[m])  
                else if p^[i]='H'then begin inc(h,dh);if h>h_h then h:=h_h;end  
                else if p^[i]='T'then m:=q^[i];  
                m:=next[m];  
                if m=1 then begin  
                        h:=h-trunc((h_tot_m-get+h_m-1)/h_m);  
                        if h<=0 then break;  
                end;  
        end;  
end;  
  
procedure sort;//排序  
begin  
        for i:=1 to 20 do begin  
                k:=i;  
                for j:=i+1 to 20 do if(harm[j]>harm[k])then k:=j;  
                po1:=p[i];p[i]:=p[k];p[k]:=po1;  
                po2:=q[i];q[i]:=q[k];q[k]:=po2;  
                t:=harm[k];harm[k]:=harm[i];harm[i]:=t;  
        end;  
end;  
  
procedure new(f:point;g:p2);var i,x:int;//生成后代  
begin  
        x:=random(10)+1;  
        for i:=1 to m_h>>1 do begin f^[i]:=p[x]^[i];g^[i]:=q[x]^[i];end;  
        x:=random(10)+1;  
        for i:=m_h>>1+1 to m_h do begin f^[i]:=p[x]^[i];g^[i]:=q[x]^[i];end;  
        for i:=1 to aa[ii] do begin  
                x:=random(m_h)+1;  
                f^[x]:=skill[random(3)];  
                if f^[x]='T'then g^[x]:=random(n)+1 else g^[x]:=0;  
        end;  
end;  
  
procedure main;//进行筛选  
begin  
        for i:=1 to 20 do harm[i]:=get(@f[i],@g[i]);  
        for i:=1 to 20 do begin p[i]:=@f[i];q[i]:=@g[i];end;  
        for i:=1 to 45000 do aa[i]:=trunc((100000-i)/10000)+1;  
        for ii:=1 to 45000 do begin  
                sort;  
                if harm[1]>=h_tot_m then begin ok:=true;exit;end;  
                for i:=10 to 20 do new(p[i],q[i]);  
                for i:=10 to 20 do harm[i]:=get(p[i],q[i]);  
        end;  
end;  
  
procedure print(x:int);var harm:int;//输出  
begin  
        writeln('VICTORIOUS');  
        get(p[x],q[x]);  
        harm:=0;m:=n;  
        for i:=1 to m_h do begin  
                write(p[x]^[i]);  
                if p[x]^[i]='T'then writeln(' ',q[x]^[i])else writeln;  
                if p[x]^[i]='L'then inc(harm,lp[m]);  
                if p[x]^[i]='T'then m:=q[x]^[i];  
                m:=next[m];  
                if(harm>=h_tot_m)then exit;  
        end;  
end;  
  
begin  
        randomize;  
        assign(input,'heroes.in');reset(input);  
        assign(output,'heroes.out');rewrite(output);  
        read(n,h_h,m_h,h_m,n_m,v_m,dh);  
        h_tot_m:=h_m*n_m;  
        for i:=1 to n do read(lp[i]);  
        for i:=1 to n do next[i]:=i-min(v_m,i-1);  
        for i:=1 to 20 do  
                for j:=1 to m_h do begin  
                        f[i,j]:=skill[random(3)];  
                        if f[i,j]='T'then g[i,j]:=random(n)+1;  
                end;  
        next[1]:=1;  
        main;  
        if ok then begin  
                for i:=1 to 20 do if harm[i]>=h_tot_m then begin print(i);break;end;  
        end else write('DEFEATED');  
        close(input);close(output);  
end. 





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值