牛客练习赛 37 C 筱玛的迷阵探险 【折半搜索+01字典树】

题目链接:https://ac.nowcoder.com/acm/contest/342/C


题目:
筱玛是个快乐的男孩子。
寒假终于到了,筱玛决定请他的朋友们一起来玩迷阵探险。
迷阵可以看做一个n×n的矩阵A,每个格子上有一个数Ai,j。
入口在左上角的(1,1)处,出口在右下角的(n,n)处。每一步都只能向下或向右移动一格。最后能获得的经验值为初始经验e与路径上经过的所有数的权值异或和。
求筱玛最大可能获得的经验值。

输入:
第一行两个整数n和e。
接下来n行,每行n个整数,描述矩阵A。

输出:
一个整数,表示筱玛最大可能获得的经验值。

 

思路:直接搜索全部会超时,用折半搜索,对角线(坐下到右上)上的所有点当字典树树根,存从起点到对角线上的点的异或和的二进制,然后从终点搜到对角线上的所的点,找到最大值;


#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<math.h>
#include<map>
#include<set>
#include<queue>
#include<vector>
#include<stack>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const double pi=acos(-1.0);
const ll mod=1e8;
const int N=2;
const int M=22;

typedef struct Node
{
    Node *Next[N];
}Node;

Node *tre[M];
int mp[M][M];
int n,e,ans;

Node * build()//建立根节点
{
    Node *node=(Node *)malloc(sizeof(Node));
    node->Next[0]=node->Next[1]=0;
    return node;
}

void tree_insert(Node *root,int x)//插入二进制
{
    int t,i=30;
    Node *p=root;
    while(i>=0)
    {
        t=(x>>i)&1;
        if(p->Next[t]==NULL)
            p->Next[t]=build();
        p=p->Next[t];
        i--;
    }
}

int tree_query(Node *root,int x)//寻找异或和最大的
{
    int res=0,t,i=30;
    Node *p=root;
    while(i>=0)
    {
        t=(x>>i)&1;
        if(p->Next[t^1]!=NULL)
        {
            res|=(1<<i);
            t^=1;
        }
        p=p->Next[t];
        i--;
    }
    return res;
}

void dfs1(int x,int y,int sum)//深搜从(0,0)到对角线(左下角到右上角)上的所有点
{
    if(x+y==n-1)
    {
        sum^=mp[x][y];
        tree_insert(tre[x],sum);
        return;
    }
    dfs1(x+1,y,sum^mp[x][y]);
    dfs1(x,y+1,sum^mp[x][y]);
}

void dfs2(int x,int y,int sum)//深搜从终点到对角线上的所有点
{
    if(x+y==n-1)
    {
        ans=max(tree_query(tre[x],sum),ans);
        return;
    }
    dfs2(x-1,y,sum^mp[x][y]);
    dfs2(x,y-1,sum^mp[x][y]);
}

int main()
{
    while(~scanf("%d %d",&n,&e))
    {
        for(int i=0;i<n;i++)
            tre[i]=build();
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
            scanf("%d",&mp[i][j]);
        ans=0;
        dfs1(0,0,e);
        dfs2(n-1,n-1,0);
        printf("%d\n",ans);
    }
    return 0;
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值