银河之星 (乱搞+记忆化搜索)

Time Limit: 1000 ms   Memory Limit: 256 MB


Description

  

 

  


题解

  乍一看真的无从下手,规则一脸懵逼。

  首先看到第3个规则,每个棋子往任意方向都只能走3格。可以联想一下国际象棋四个象,2个永远在黑格,2个永远在白格。

  依照这个思路,我们只有9类位置(横坐标模3与纵坐标模3都相同的位置为同一类)。

  其中,每一类位置上的棋子可以通过规则3互达同一类位置,却永远不可能用规则3走到其他类的位置。

  如下图:(想象若干个3x3的框,左上角对齐铺满整个地图,框内位置相同的即同类位置)

  

  

  我们把同类位置的棋子数量求和一下,对应放到一个3x3的九宫格里(我们按照上图以0~8为每类位置编号)。以下就只对这个九宫格操作就可以了,比如$x$个0类的棋子越过1个8类棋子到达4类位置,我们把0的数字减$x$,把8的数字减$x$,把4的数字加$x$。

  为什么不用考虑实际上棋子的位置呢?

  根据上面标红的性质,任意同类棋子可以互达。我不需要考虑我要操作的3枚棋子具体在什么地方,只要将这3枚棋子移到三点一线,就可以进行规则2的操作了。

没完

  然而不是每三个位置都能移成三点一线的,受地图大小影响,可能会出现这种情况:

  

  比如这个案例,对于7-->8-->6的情况,我能用九宫格的数字相加减吗?7-->5-->0呢?都不行。因为实际地图上,并不存在一个786、750三点一线的地方。但是0-->6-->3、1-->7-->4、0-->7-->5都是可以用九宫格的数字进行加减操作的,因为地图的确存在这种场所可以供棋子移动过来进行操作

搞啊

  那么我们预处理出那些类别的位置可以走2步互达(枚举原图的位置往八个方向走2步看看走到的是什么类别的位置)。

  考虑到棋子总数只有10,我们可以用状态压缩记录这个九宫格的状态,暴力枚举即可,用map记忆一下有没有到过这个状态。

  终止状态即:指定终点同类位置的权值为1,且其他位置权值为0.



 1 #include <cstdio>
 2 #include <map>
 3 #define min(a,b) (a<b?a:b)
 4 using namespace std;
 5 typedef long long ll;
 6 const int base=11,xx[8]={-1,-1,-1,0,0,1,1,1},yy[8]={-1,0,1,-1,1,-1,0,1};
 7 int k,n,m,x0,y0;
 8 int can[9][9];
 9 ll bin[10],bigsta,finsta;
10 map<ll,int> ans;
11 inline int trans(int x){return x%3;}
12 void getDirection(){
13     for(int i=0;i<9;i++)
14         for(int j=0;j<9;j++) can[i][j]=0;
15     int u,v,x,y;
16     for(int i=0;i<n;i++)
17         for(int j=0;j<m;j++){
18             u=trans(i)*3+trans(j);
19             for(int k=0;k<8;k++){
20                 x=i+xx[k]*2; y=j+yy[k]*2;
21                 if(x<0||x>=n||y<0||y>=m) continue;
22                 v=trans(x)*3+trans(y);
23                 can[u][v]=can[v][u]=1;
24             }
25         }
26 }
27 bool dfs(ll s){
28     if(s==finsta) return true;
29     if(ans[s]) return ans[s]==1;
30     int now[3][3];
31     ll t=s;
32     for(int i=8;i>=0;i--){
33         now[i/3][i%3]=t/bin[i];
34         t%=bin[i];
35     }
36     int u,v,p,x,y,px,py;
37     for(int i=0;i<3;i++)
38         for(int j=0;j<3;j++){
39             u=i*3+j;
40             for(int k=0;k<8;k++){
41                 px=i+xx[k]; py=j+yy[k];
42                 x=i+xx[k]*2; y=j+yy[k]*2;
43                 px=(px+9)%3; py=(py+9)%3; x=(x+9)%3; y=(y+9)%3;
44                 p=px*3+py; v=x*3+y;
45                 if(!can[u][v]) continue;
46                 int delta=min(now[i][j],now[px][py]);
47                 for(int g=1;g<=delta;g++)
48                     if(dfs(s-bin[p]*g-bin[u]*g+bin[v]*g)) return true;
49             }
50         }
51     ans[s]=2;
52     return false;
53 }
54 int main(){
55     bin[0]=1;
56     for(int i=1;i<=9;i++) bin[i]=bin[i-1]*base;
57     while(~scanf("%d%d%d%d%d",&k,&n,&m,&x0,&y0)){
58         ans.clear();
59         x0=trans(x0-1); y0=trans(y0-1);
60         finsta=bin[x0*3+y0];
61         getDirection();
62         bigsta=0;
63         for(int i=1,x,y;i<=k;i++){
64             scanf("%d%d",&x,&y);
65             x=trans(x-1); y=trans(y-1);
66             bigsta+=bin[x*3+y];
67         }
68         if(dfs(bigsta)) printf("Yes\n");
69         else printf("No\n");
70     }
71     return 0;
72 }

奇妙代码

时间: 2024-09-29 20:37:52

银河之星 (乱搞+记忆化搜索)的相关文章

tyvj 1004 滑雪 记忆化搜索

滑雪 Time Limit: 1 Sec  Memory Limit: 256 MB 题目连接 http://www.tyvj.cn/p/1004 Description trs喜欢滑雪.他来到了一个滑雪场,这个滑雪场是一个矩形,为了简便,我们用r行c列的矩阵来表示每块地形.为了得到更快的速度,滑行的路线必须向下倾斜.    例如样例中的那个矩形,可以从某个点滑向上下左右四个相邻的点之一.例如24-17-16-1,其实25-24-23…3-2-1更长,事实上这是最长的一条. Input 输入文件

BZOJ 3895 取石子 博弈论+记忆化搜索

题目大意:给定n堆石子,两人轮流操作,每个人可以合并两堆石子或拿走一个石子,不能操作者输,问是否先手必胜 直接想很难搞,我们不妨来考虑一个特殊情况 假设每堆石子的数量都>1 那么我们定义操作数b为当前石子总数+当前堆数-1 若b为奇数,则先手必胜,否则后手必胜 证明: 若当前只有一堆,则正确性显然 否则: 若b为奇数,那么先手只需进行一次合成操作,此时操作数会-1,且仍不存在大小为1的堆 因此只需要证明b为偶数时先手必败即可 若先手选择了合成操作,那么操作数-1且不存在大小为1的堆,状态回到了b

C语言记忆化搜索___漫步校园(Hdu 1428)

Problem Description LL最近沉迷于AC不能自拔,每天寝室.机房两点一线.由于长时间坐在电脑边,缺乏运动.他决定充分利用每次从寝室到机房的时间,在校园里散散步.整个HDU校园呈方形布局,可划分为n*n个小方格,代表各个区域.例如LL居住的18号宿舍位于校园的西北角,即方格(1,1)代表的地方,而机房所在的第三实验楼处于东南端的(n,n).因有多条路线可以选择,LL希望每次的散步路线都不一样.另外,他考虑从A区域到B区域仅当存在一条从B到机房的路线比任何一条从A到机房的路线更近(

UVALive 6470 Chomp --记忆化搜索

题意:给一个只有三行的方块阵(横向最多100个),然后p,q,r分别代表第1,2,3层的方格数,两人轮流去掉一个格子,此时这个格子的右上方都会被去掉,面临只剩最左下角的一个格子的状态的人输,问先手能否赢,要赢得话应该取哪个方格. 解法:记忆化搜索,设dp[p][q][r]表示第1,2,3层方格数分别为p,q,r的输赢状态,0为输,1为赢,X[][][],Y[][][]分别表示其该取的方格坐标.每次求dp[p][q][r]时,枚举能达到的状态,如果这些状态的输赢值有一个为输,则此状态一定为赢,返回

ACM-ICPC 2018 徐州赛区网络预赛 B BE, GE or NE(博弈,记忆化搜索)

链接https://nanti.jisuanke.com/t/31454 思路 开始没读懂题,也没注意看数据范围(1000*200的状态,记忆化搜索随便搞) 用记忆化搜索处理出来每个状态的胜负情况 因为每个人都会选择最优的,因此记忆化搜索的过程其实就是在模拟两个人每一步决策所带来的胜负情况, 只要返回一个必胜,就直接返回(因为会选择最优) 然后在没有返回必胜的状态下,有平局就选择平局,没有平局就只能输了 #include<bits/stdc++.h> #define st 100 #defin

P2921 [USACO08DEC]在农场万圣节Trick or Treat on the Farm 记忆化搜索dfs

题目描述 每年,在威斯康星州,奶牛们都会穿上衣服,收集农夫约翰在N(1<=N<=100,000)个牛棚隔间中留下的糖果,以此来庆祝美国秋天的万圣节. 由于牛棚不太大,FJ通过指定奶牛必须遵循的穿越路线来确保奶牛的乐趣.为了实现这个让奶牛在牛棚里来回穿梭的方案,FJ在第i号隔间上张贴了一个“下一个隔间”Next_i(1<=Next_i<=N),告诉奶牛要去的下一个隔间:这样,为了收集它们的糖果,奶牛就会在牛棚里来回穿梭了. FJ命令奶牛i应该从i号隔间开始收集糖果.如果一只奶牛回到某

HDU 1513 Palindrome:LCS(最长公共子序列)or 记忆化搜索

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1513 题意: 给你一个字符串s,你可以在s中的任意位置添加任意字符,问你将s变成一个回文串最少需要添加字符的个数. 题解1(LCS): 很神奇的做法. 先求s和s的反串的LCS,也就是原串中已经满足回文性质的字符个数. 然后要变成回文串的话,只需要为剩下的每个落单的字符,相应地插入一个和它相同的字符即可. 所以答案是:s.size()-LCS(s,rev(s)) 另外,求LCS时只会用到lcs[i-

uva 1076 - Password Suspects(AC自动机+记忆化搜索)

题目链接:uva 1076 - Password Suspects 题目大意:有一个长度为n的密码,存在m个子串,问说有多少种字符串满足,如果满足个数不大于42,按照字典序输出. 解题思路:根据子串构建AC自动机,然后记忆化搜索,dp[i][u][s]表示第i个字符,在u节点,匹配s个子串. #include <cstdio> #include <cstring> #include <queue> #include <string> #include <

poj 1579(动态规划初探之记忆化搜索)

Function Run Fun Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 17843   Accepted: 9112 Description We all love recursion! Don't we? Consider a three-parameter recursive function w(a, b, c): if a <= 0 or b <= 0 or c <= 0, then w(a, b