【JZOJ4824】【NOIP2016提高A组集训第1场10.29】配对游戏
题目描述
流行的跳棋游戏是在一个有m*n个方格的长方形棋盘上玩的。棋盘起初全部被动物或障碍物占满了。在一个方格中,‘X’表示一个障碍物,一个‘0’~‘9’的个位数字表示一个不同种类的动物,相同的个位数字表示相同种类的动物。一对动物只有当它们属于同一种类时才可以被消去。消去之后,他们所占的方格就成为空方格,直到游戏结束。要消去一对动物的前提条件是:这对候选动物所在的方格必须相邻,或它们之间存在一条通路。棋盘上一个方格只和其上下左右的方格相邻。一条通路是由一串相邻的空方格组成。路的长度则是通路中空方格的数目。你要输出可被消去的动物的最多对数,以及在此操作过程中,最小的通路长度总和。
数据范围
N,M<=5
解法
暴力+剪枝
正确性可以保证,时间效率较低;
可以考虑牺牲点正确性以提高时间效率。
A*
正确性和时间效率取决于估价函数。
带策略的暴力
正确性勉强,时间效率卡常数;
贪心
正确性无法保证,时间效率高;
所以可以考虑牺牲时间效率,多次求解求最优。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const char* fin="pair.in";
const char* fout="pair.out";
const int inf=0x7fffffff;
const int maxn=13,maxm=maxn*maxn;
const int h[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
int n,m,i,j,k,maxx,ans1,ans2,interesting=5,hx,hy,ans3,ans4;
char a[maxn][maxn];
bool bz[maxn][maxn];
int b[maxm][2],head,tail,c[6];
int f[maxn][maxn];
int heavy(int x,int y){
return max(abs(x-hx),abs(y-hy));
}
void add(int x,int y,int z,int awful){
if (z>=f[x][y] || (!bz[x][y] && awful==0) || a[x][y]=='X') return ;
b[++tail][0]=x;
b[tail][1]=y;
f[x][y]=z;
}
int getdis(int x,int y,int u,int v){
int i,j,k,ans=inf;
memset(f,127,sizeof(f));
head=tail=0;
add(x,y,0,1);
while (head++<tail){
for (i=0;i<4;i++){
j=b[head][0]+h[i][0];
k=b[head][1]+h[i][1];
if (j>0 && j<=n && k>0 && k<=m)
if (j==u && k==v) ans=min(f[b[head][0]][b[head][1]],ans);
else add(j,k,f[b[head][0]][b[head][1]]+1,0);
}
}
return ans;
}
void work(int x,int y){
int i,j,k,minx=10000,mnid[2],mminx=inf;
for (i=1;i<=n;i++)
for (j=1;j<=m;j++)
if (!bz[i][j] && a[i][j]==a[x][y]){
if (x==i && y==j) continue;
k=getdis(x,y,i,j);
if (k<minx || k==minx && heavy(i,j)<mminx){
minx=k;
mminx=heavy(i,j);
mnid[0]=i;
mnid[1]=j;
}
}
if (minx==10000) return;
else{
/*ans1++;
ans2+=minx;
bz[x][y]=true;
bz[mnid[0]][mnid[1]]=true;*/
if (c[1]>minx){
c[1]=minx;
c[2]=x;
c[3]=y;
c[4]=mnid[0];
c[5]=mnid[1];
}
}
}
void solve(int v){
int i,j,k;
while (1){
c[1]=10000;
for (i=v;i<=n-v+1;i++) if (!bz[i][m-v+1] && a[i][m-v+1]!='X') work(i,m-v+1);
for (i=m-v+1;i>=v;i--) if (!bz[i][v] && a[i][v]!='X') work(i,v);
for (i=v;i<=n-v+1;i++) if (!bz[n-v+1][i] && a[n-v+1][i]!='X') work(n-v+1,i);
for (i=m-v+1;i>=v;i--) if (!bz[v][i] && a[v][i]!='X') work(v,i);
if (c[1]<10000){
bz[c[2]][c[3]]=true;
bz[c[4]][c[5]]=true;
ans1++;
ans2+=c[1];
}else break;
}
}
int main(){
freopen(fin,"r",stdin);
freopen(fout,"w",stdout);
scanf("%d%d",&n,&m);
for (i=1;i<=n;i++) scanf("%s",a[i]+1);
maxx=min((n+1)/2,(m+1)/2);
for (hx=1;hx<=n;hx++)
for (hy=1;hy<=m;hy++){
memset(bz,0,sizeof(bz));
ans1=ans2=0;
for (i=1;i<=maxx;i++){
for (j=i;j;j--){
solve(j);
}
}
if (ans1>ans3 || ans1==ans3 && ans2<ans4){
ans3=ans1;
ans4=ans2;
}
}
for (hx=1;hx<=n;hx++)
for (hy=1;hy<=m;hy++){
memset(bz,0,sizeof(bz));
ans1=ans2=0;
for (i=maxx;i;i--){
for (j=i;j;j--){
solve(j);
}
}
if (ans1>ans3 || ans1==ans3 && ans2<ans4){
ans3=ans1;
ans4=ans2;
}
}
for (hx=1;hx<=n;hx++)
for (hy=1;hy<=m;hy++){
memset(bz,0,sizeof(bz));
ans1=ans2=0;
for (i=maxx;i;i--){
for (j=1;j<=maxx;j++){
solve(j);
}
}
if (ans1>ans3 || ans1==ans3 && ans2<ans4){
ans3=ans1;
ans4=ans2;
}
}
for (hx=1;hx<=n;hx++)
for (hy=1;hy<=m;hy++){
memset(bz,0,sizeof(bz));
ans1=ans2=0;
for (i=1;i<=maxx;i++){
for (j=i;j;j--){
solve(j);
}
}
if (ans1>ans3 || ans1==ans3 && ans2<ans4){
ans3=ans1;
ans4=ans2;
}
}
printf("%d %d",ans3,ans4);
return 0;
}
启发
这种题常出现在NOIP提高组的压轴题,
往往没有稳定复杂度的算法。
此时就要考虑上述几种做法,进行取舍,以骗得最高的分数。
大致上就是平衡时间效率和正确性。
此外还有考虑编程复杂度的问题,以我的观点:
贪心的编程复杂度最简单,也最容易调试;
因为贪心的每一次操作具有后效性。
【JZOJ4824】【NOIP2016提高A组集训第1场10.29】配对游戏的更多相关文章
- 【NOIP2016提高A组集训第1场10.29】配对游戏
题目 流行的跳棋游戏是在一个有mn个方格的长方形棋盘上玩的.棋盘起初全部被动物或障碍物占满了.在一个方格中,'X'表示一个障碍物,一个'0'-'9'的个位数字表示一个不同种类的动物,相同的个位数字表示 ...
- 【NOIP2016提高A组集训第1场10.29】完美标号
题目 给定M个二元组(A_i, B_i),求X_1, ..., X_N满足:对于任意(A_i, B_i),有|X_{A_i} - X_{B_i}| = 1成立. 分析 显然,对于二元组(x,y),X_ ...
- 【NOIP2016提高A组集训第3场10.31】高维宇宙
题解 分析 因为只有奇数和偶数配对才有可能得出质数, 暴力求出每一对\(a_i+a_j\)为质数,将其中的奇数想偶数连一条边. 二分图匹配,匈牙利算法. #include <cmath> ...
- 【JZOJ4831】【NOIP2016提高A组集训第3场10.31】方程式
题目描述 数据范围 解法 枚举根之后,使用大除法. 代码 #include<stdio.h> #include<iostream> #include<string.h&g ...
- 【JZOJ4832】【NOIP2016提高A组集训第3场10.31】高维宇宙
题目描述 数据范围 解法 由于大于4的素数只有可能由奇数和偶数的和得出. 所以根据数的奇偶性可以分出两类数奇数和偶数. 奇数之间不会相互匹配,偶数之间也不会相互匹配. 那么原问题转化为二分图最大匹配. ...
- 【JZOJ4833】【NOIP2016提高A组集训第3场10.31】Mahjong
题目描述 解法 搜索. 代码 #include<stdio.h> #include<iostream> #include<string.h> #include< ...
- JZOJ 【NOIP2016提高A组集训第16场11.15】兔子
JZOJ [NOIP2016提高A组集训第16场11.15]兔子 题目 Description 在一片草原上有N个兔子窝,每个窝里住着一只兔子,有M条路径连接这些窝.更特殊地是,至多只有一个兔子窝有3 ...
- JZOJ 【NOIP2016提高A组集训第16场11.15】SJR的直线
JZOJ [NOIP2016提高A组集训第16场11.15]SJR的直线 题目 Description Input Output Sample Input 6 0 1 0 -5 3 0 -5 -2 2 ...
- 【NOIP2016提高A组集训第4场11.1】平衡的子集
题目 夏令营有N个人,每个人的力气为M(i).请大家从这N个人中选出若干人,如果这些人可以分成两组且两组力气之和完全相等,则称为一个合法的选法,问有多少种合法的选法? 分析 如果暴力枚举每个人被分到哪 ...
随机推荐
- Java IO : NIO与IO的区别
参考资料:https://dzone.com/articles/java-nio-vs-io NIO是面向流的,IO是面向缓冲流的. NIO是非线程阻塞的,IO是线程阻塞的. NIO的Selector ...
- Matlab中的cell、size函数
参考网址:http://blog.sina.com.cn/s/blog_5efed5800100exmj.html Cell函数 如果p为一个数,那么h(1)=p,是没有问题的. 如果p为一个向量,那 ...
- 字符界面总是显示 login incorrect
一般来说出现这样的提示,是因为登陆的密码错误,如果密码中有数字,最好用主键盘输入,用数字键盘会有错误.
- TZ_05_Spring_annotation常见注解
Spring常用的注解大全和解释 注解 解释 @Controller 组合注解(组合了@Component注解),应用在MVC层(控制层),DispatcherServlet会自动扫描注解了此注解的类 ...
- 汉诺塔III HDU - 2064
汉诺塔III HDU - 2064 约19世纪末,在欧州的商店中出售一种智力玩具,在一块铜板上有三根杆,最左边的杆上自上而下.由小到大顺序串着由64个圆盘构成的塔.目的是将最左边杆上的盘全部移到右 ...
- python自动化---各类发送邮件方法及其可能的错误
一.发送文本邮件 可能的问题1.:需要注意,目前QQ邮箱来讲,不能收到完整的邮件,即有些内容不能显示,最好全部使用网易邮箱: 可能的问题2.:在以往的文本邮件发送中,只写了 msg = MIMETex ...
- MobaXterm实时查看Linux服务器上的日志
一.工具 MobaXterm介绍 https://blog.csdn.net/juyin2015/article/details/79056687/ 1.,点击Session 输入服务器IP.用户名 ...
- 【模板】Tarjan缩点,强连通分量 洛谷P2341 [HAOI2006]受欢迎的牛 [2017年6月计划 强连通分量01]
P2341 [HAOI2006]受欢迎的牛 题目描述 每头奶牛都梦想成为牛棚里的明星.被所有奶牛喜欢的奶牛就是一头明星奶牛.所有奶 牛都是自恋狂,每头奶牛总是喜欢自己的.奶牛之间的“喜欢”是可以传递的 ...
- 转:解决Onethink上传视频的问题 超棒的解决方案
用过Onethink的都知道,它是不能上传视频的. 有人想到用上传附件的方式上传视频,但是结果……就是提示没有上传文件. 要是正常上传个一两兆的图片啊,压缩文件什么的还是可以的. 所以,重点来了 怎么 ...
- Fitnesse批量读取变量信息,并保存到用例执行上下文中
Fitnesse变量可以分成两种,一种是自定义变量,另一种是用例执行过程中的临时变量. 在Finesse使用过程中,如果需要定义一些公共的变量,可以统一在一个文件中使用自定义变量的方法,将公共变量全部 ...