题目描述

流行的跳棋游戏是在一个有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】配对游戏的更多相关文章

  1. 【NOIP2016提高A组集训第1场10.29】配对游戏

    题目 流行的跳棋游戏是在一个有mn个方格的长方形棋盘上玩的.棋盘起初全部被动物或障碍物占满了.在一个方格中,'X'表示一个障碍物,一个'0'-'9'的个位数字表示一个不同种类的动物,相同的个位数字表示 ...

  2. 【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_ ...

  3. 【NOIP2016提高A组集训第3场10.31】高维宇宙

    题解 分析 因为只有奇数和偶数配对才有可能得出质数, 暴力求出每一对\(a_i+a_j\)为质数,将其中的奇数想偶数连一条边. 二分图匹配,匈牙利算法. #include <cmath> ...

  4. 【JZOJ4831】【NOIP2016提高A组集训第3场10.31】方程式

    题目描述 数据范围 解法 枚举根之后,使用大除法. 代码 #include<stdio.h> #include<iostream> #include<string.h&g ...

  5. 【JZOJ4832】【NOIP2016提高A组集训第3场10.31】高维宇宙

    题目描述 数据范围 解法 由于大于4的素数只有可能由奇数和偶数的和得出. 所以根据数的奇偶性可以分出两类数奇数和偶数. 奇数之间不会相互匹配,偶数之间也不会相互匹配. 那么原问题转化为二分图最大匹配. ...

  6. 【JZOJ4833】【NOIP2016提高A组集训第3场10.31】Mahjong

    题目描述 解法 搜索. 代码 #include<stdio.h> #include<iostream> #include<string.h> #include< ...

  7. JZOJ 【NOIP2016提高A组集训第16场11.15】兔子

    JZOJ [NOIP2016提高A组集训第16场11.15]兔子 题目 Description 在一片草原上有N个兔子窝,每个窝里住着一只兔子,有M条路径连接这些窝.更特殊地是,至多只有一个兔子窝有3 ...

  8. 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 ...

  9. 【NOIP2016提高A组集训第4场11.1】平衡的子集

    题目 夏令营有N个人,每个人的力气为M(i).请大家从这N个人中选出若干人,如果这些人可以分成两组且两组力气之和完全相等,则称为一个合法的选法,问有多少种合法的选法? 分析 如果暴力枚举每个人被分到哪 ...

随机推荐

  1. mysql 如果处理货币金钱类型

    我们知道,数据库存金钱类型可以float.double.decimal ,相比较而已decimal 最好用. 好吧, 我们公司用的分为单位, 类型 用bigint 存取,操作的时候到是很方便, 展示的 ...

  2. Python之通配符--提取文件中的内容并输出

    前言:我的学习进度其实没有那么快的,因为现在是网络工程师实习,只有晚上一点时间和周末有空,所以周一到周天的学习进度很慢,今天之所以突然跳到通配符是因为工作需要,大体讲一下我的工作需求:网络工程师就是写 ...

  3. Leetcode441Arranging Coins排列硬币

    你总共有 n 枚硬币,你需要将它们摆成一个阶梯形状,第 k 行就必须正好有 k 枚硬币. 给定一个数字 n,找出可形成完整阶梯行的总行数. n 是一个非负整数,并且在32位有符号整型的范围内. 示例 ...

  4. vue之this.$route.params和this.$route.query的区别

    1.this.$route.query的使用 A.传参数: this.$router.push({          path: '/monitor',          query:{       ...

  5. bzoj 1800 [Ahoi2009]fly 飞行棋——模拟

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1800 原来只想到一个弧是一条边. 然后发现不是.差点不会做.经Zinn提醒,不用枚举那条边由 ...

  6. PHP实现微信申请退款流程实例源码

    https://www.jb51.net/article/136476.htm 目录 前期准备: 前面讲了怎么实现微信支付,详见博文:PHP实现微信支付(jsapi支付)流程  和ThinkPHP中实 ...

  7. 直接在安装了redis的Linux机器上操作redis数据存储类型--对key的操作

    一.概述:   前几篇博客中,主要讲述的是与Redis数据类型相关的命令,如String.List.Set.Hashes和Sorted-Set.这些命令都具有一个共同点,即所有的操作都是针对与Key关 ...

  8. Java问题解读系列之String相关---String类为什么是final的?

    今天看到一篇名为<Java开发岗位面试题归类汇总>的博客,戳进去看了一下题目,觉得有必要夯实一下基本功了,所以打算边学边以博客的形式归纳总结,每天一道题, 并将该计划称为java问题解读系 ...

  9. jnhs中国的省市县区邮编坐标mysql数据表

    https://blog.csdn.net/sln2432713617/article/details/79412896 -- 1.之前项目中需要全国的省市区数据,在网上找了很多,发现数据要么不全,要 ...

  10. ssh连接超时中断问题解决方案

    当在终端使用ssh命令连接到服务器时,如果一段时间没有活动连接会被中断,以下有两种方案可以解决: 一.修改ssh客户端配置 编辑客户端 /etc/ssh/ssh_config (或~/.ssh/con ...