poj 1085 (Triangle War)状压dp+记忆化搜索

本文介绍了一种使用状态压缩动态规划解决特定三角形游戏中玩家得分最大化的算法实现。通过预处理边与三角形的关系及状态转移,实现了高效求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:点击打开链接

题意:两个人轮流在九个小正三角形组成的大三角形上面选取边,不能重复选取,如果一个玩家选取的某条边后能组成新的小三角形,则该玩家得分为新组成三角形的个数,且进行下一次选择,比赛结束后谁的分值高谁获胜。

DP[status]表示的是当前局势下,该玩家到游戏结束最多可以得到多少分(取分差绝对值~~)

题目本身不算难,麻烦的是把题目输出每条边对应到指定的压缩的状态以及判断玩家的得分~~~

(好麻烦啊,好麻烦啊,我的转化成状态的思路全部写在init()函数里面了,逃~~~)

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
//状态压缩+DP
const int inf=0x3f3f3f3f;
int dp[1<<18];
int edge[12][12];
int tri[12];
//idx是新加的边,计算新加的边能构成多少个三角形
int calculate(int status,int idx)
{
    int ret=0;
    for(int i=0;i<9;i++)
        if(((1<<idx)&tri[i])&&((status&tri[i])==tri[i])) ret++;
    return ret;
}
//预处理出所有状态,方便后续处理
void init()
{
    memset(edge,-1,sizeof(edge));
    edge[1][2]=0;edge[1][3]=1;edge[2][3]=2;
    edge[2][4]=3;edge[2][5]=4;edge[4][5]=5;
    edge[3][5]=6;edge[3][6]=7;edge[5][6]=8;
    edge[4][7]=9;edge[4][8]=10;edge[7][8]=11;
    edge[5][8]=12;edge[5][9]=13;edge[8][9]=14;
    edge[6][9]=15;edge[6][10]=16;edge[9][10]=17;
    for(int i=0;i<6;i++)
    {
        int status1=1<<(i*3);
        int status2=1<<(i*3+1);
        int status3=1<<(i*3+2);
        int status=status1|status2|status3;
        tri[i]=status;
    }
    const int rev[][3]={{2,4,6},{5,10,12},{8,13,15}};
    for(int i=0;i<4;i++)
    {
        int status1=1<<rev[i][0];
        int status2=1<<rev[i][1];
        int status3=1<<rev[i][2];
        int status=status1|status2|status3;
        tri[i+6]=status;
    }
}
//DP表示的是当前局势下,该玩家到游戏结束最多可以得到多少分
int dfs(int status)
{
    if(dp[status]) return dp[status];
    if(status==((1<<18)-1)) return 0;
    int ret=-inf;
    for(int i=0;i<18;i++)
        if((status&(1<<i))==0)
        {
            int status2=status|(1<<i);
            int cal=calculate(status2,i);
            if(cal) ret=max(ret,cal+dfs(status2));
            else ret=max(ret,-dfs(status2));
        }
    return dp[status]=ret;
}
int main()
{
    int t,nofcase=1;
    init();
    scanf("%d",&t);
    while(t--)
    {
        int n;
        scanf("%d",&n);
        int person=0,score=0,status=0;
        int cal;
        for(int i=0;i<n;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            status|=(1<<edge[u][v]);
            cal=calculate(status,edge[u][v]);
            if(cal) score+=(person==0?1:-1)*cal;
            else person^=1;
        }
        if(person==0) score+=dfs(status);
        else score-=dfs(status);
        printf("Game %d: %c wins.\n",nofcase++,score>0?'A':'B');
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值