zoukankan      html  css  js  c++  java
  • HDU4753 Fishhead’s Little Game——2013 ACM/ICPC Asia Regional Nanjing Online

    今天比赛又是做得好水的。被狂虐啊。

    比赛两个多小时一直没出题,遒遒最先交的若干发都wa了。T_T

    我独自在一遍苦思了1006这个题,还好最后把这个题目A掉了,不然又是深坑队友。

    题目的意思我就不多说了,直接去hdu上看题意,题意很容易懂。

    这里说一下我的解题思路吧。

    首先题目总共有24条边这是不会变得,但是每次刚开始的一些条件是作为已知条件给你的,所以你不用考虑读数时候游戏者的智商问题。

    对于已知的步奏,我们只要模拟,并且记录两个人的得分就可以了。

    关键是后面怎么去处理呢?

    其实这个题目有一个关键的条件,虽然总边数有24,但是未知的边数只有12,12是个很小的数字,于是总共可能的状态数只有2^12个,可以用状态压缩dp搞定啦。

    但是这个题目还涉及到一些博弈论的知识,简单的说一下吧!

    首先说明两个名词,必胜态和必败态。顾名思义,名词我就不解释了。

    接下来就是怎么判断一个状态是否必胜态或者必败态。(会不会有中间态?显然不会,不解释)

    当前状态是必胜态,当且仅当存在它的某一个下一步状态为必败态;当前状态是必败态,当且仅当它的所有的下一步状态全部都是必胜态。

    好好理解上一步这句话。

    这个题目需要我们记录的可不仅仅是必胜还是必败,还要我们每个状态记录到底是胜了多少分还是败了多少分?有了这里我们就可以dp了。

    我们用一个数组(我在代码中用的是ans1[x])来记录x状态先手的人以最优策略能够胜对方多少分。

    用二进制(最多12个0)表示初始状态,即所有的地方都没有填成实线。

    显然最终的状态(也就是全部为1的时候,111111……)其所对应的ans1的值为0,因为可以理解为最终都取完了,两个人都不取了,所以差值为0,

    于是我们倒推,从1多的数推向1少的数,最终算出0,也就是当前这个人以最优策略能够胜对方多少分!(不用记录每个人的得分,因为得分高并比一定是最优解)

    下面我稍微指出来题目的几个小坑吧,都是泪堆出来的惨痛教训!

    1.前一段读数的时候要把放过的边全部存起来,同时还要统计两个人的分别得分。

    2.虽然游戏从一开始的时候是Tom200开始填充实线的,但是如果读数的时候n为奇数说明dp的时候是Jerry404第一个开始填充的(这里特别要注意)

    3.这也不算是坑吧,就是要建立起两点与边的对应关系,同时还要给边编号,dp的每一位是表示的边的状态,不是点哦。

    下面上我的代码(巨挫),比赛的时候写的,很难看,请谅解。(中间有两个函数功能其实是一样的,是我写挫了)

    如果觉得太难看,我觉得我上面讲得已经十分明白了,自己直接写吧。我的太难看了。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    
    int f1[30],f2[30],a[30][30],p[25],q[25],t,n,x,y,ans[2],ans1[5000],ans2[5000];
    
    void codeit()
    {
        int N=0;
        for (int i=1; i<16; i++)
        {
            if (i%4==0) continue;
            a[i][i+1]=++N;
        }
        for (int i=1; i<=12; i++) a[i][i+4]=++N;
        f1[1]=13,f1[2]=14,f1[3]=15;
        f1[4]=17,f1[5]=18,f1[6]=19;
        f1[7]=21,f1[8]=22,f1[9]=23;
        for (int i=1; i<=9; i++) f1[f1[i]]=i;
    }
    
    void add(int& ANS,int now)
    {
        int pp[25],pre=0;
        memset(pp,-1,sizeof pp);
        for (int i=1; i<=24; i++) pp[i]=p[i];
        if (now<=12)
        {
            if (now>=10)
            {
                now-=3;
                if (pp[f1[now]]==0 && pp[f1[now]+1]==0 && pp[now]==0) pre++;
            }
            else
            {
                if (pp[f1[now]]==0 && pp[f1[now]+1]==0 && pp[now+3]==0) pre++;
                if (now>3)
                {
                    now-=3;
                    if (pp[f1[now]]==0 && pp[f1[now]+1]==0 && pp[now]==0) pre++;
                }
            }
        }
        else
        {
            if (now%4==1)
            {
                if (pp[f1[now]]==0 && pp[f1[now]+3]==0 && pp[now+1]==0) pre++;
            }
            else
            {
                if (now%4!=0)
                {
                    if (pp[f1[now]]==0 && pp[f1[now]+3]==0 && pp[now+1]==0) pre++;
                }
                now--;
                if (pp[now]==0 && pp[f1[now]]==0 && pp[f1[now]+3]==0) pre++;
            }
        }
        ANS+=pre;
    }
    
    int count(int cur,int now)//在cur的状态下加入第now条边
    {
        //cout<<"now add: "<<cur<<' '<<now<<endl;
        int pp[25],pre=0;
        memset(pp,-1,sizeof pp);
        for (int i=1; i<=24; i++) if (p[i]==0) pp[i]=0;
        for (int i=1; i<=n; i++) { if ((cur&(1<<(i-1)))) pp[q[i]]=0; /*cout<<q[i]<<" q[i] 
    ";*/ }
        //for (int i=1; i<=24; i++) if (pp[i]==0) cout<<i<<' '; else cout<<0<<' '; cout<<endl;
        now=q[now]; //cout<<"adding : "<<now<<endl;
        if (now<=12)
        {
            if (now>=10)
            {
                now-=3;
                if (pp[f1[now]]==0 && pp[f1[now]+1]==0 && pp[now]==0) pre++;
            }
            else
            {
                if (pp[f1[now]]==0 && pp[f1[now]+1]==0 && pp[now+3]==0) pre++;
                if (now>3)
                {
                    now-=3;
                    if (pp[f1[now]]==0 && pp[f1[now]+1]==0 && pp[now]==0) pre++;
                }
            }
        }
        else
        {
            if (now%4==1)
            {
                if (pp[f1[now]]==0 && pp[f1[now]+3]==0 && pp[now+1]==0) pre++;
            }
            else
            {
                if (now%4!=0)
                {
                    if (pp[f1[now]]==0 && pp[f1[now]+3]==0 && pp[now+1]==0) pre++;
                }
                now--;
                if (pp[now]==0 && pp[f1[now]]==0 && pp[f1[now]+3]==0) pre++;
            }
        }
        return pre;
    }
    
    int main()
    {
        int cas=0;
        codeit();
        scanf("%d",&t);
        while (t--)
        {
            int tot,tep;
            memset(p,-1,sizeof p);
            memset(ans,0,sizeof ans);
            memset(q,0,sizeof q);
            scanf("%d",&n);
            for (int i=1; i<=n; i++)
            {
                scanf("%d%d",&x,&y);
                if (x>y) swap(x,y);
                add(ans[i%2],a[x][y]);
                p[a[x][y]]=0;
            }
            int N=0;
            for (int i=1; i<=24; i++)
            {
                if (p[i]==-1) q[++N]=i;
            }
            /*for (int i=1; i<=24; i++)
                if (q[i]>0) cout<<i<<" : "<<q[i]<<endl;   cout<<"q[i] 
    ";*/
            n=24-n;
            tot=(1<<n)-1;
            for (int i=0; i<tot; i++) ans1[i]=-999;
            ans1[tot]=0;
            for (int i=tot; i>=0; i--)
            {
                for (int j=1; j<=n; j++)
                {
                    if ((i&(1<<(j-1)))==0)
                    {
                        tep=count(i,j);
                        int next=i|(1<<(j-1));
                        if (tep-ans1[next]>ans1[i]) ans1[i]=tep-ans1[next];
                    }
                }
            }
            /*for (int i=1; i<=10; i++) cout<<ans1[i]<<' '; cout<<endl;*/
            if (n%2==1) ans1[0]=-ans1[0];
            if (ans[1]+ans1[0]>ans[0]) printf("Case #%d: Tom200
    ",++cas);
            else printf("Case #%d: Jerry404
    ",++cas);
        }
        return 0;
    }

    如有转载,请注明出处(http://www.cnblogs.com/lochan)
  • 相关阅读:
    Resharper Visual studio中的插件
    MVC 中Simditor上传本地图片
    MVC编程模型
    数据库面试题
    SQL、索引
    存储过程详解
    EF的简单认识
    MVC是什么
    AOP面向切面编程
    SQL语句基本
  • 原文地址:https://www.cnblogs.com/lochan/p/3332047.html
Copyright © 2011-2022 走看看