SWUN 1425 - 疯狂的马儿

2024-01-31 09:50
文章标签 疯狂 1425 马儿 swun

本文主要是介绍SWUN 1425 - 疯狂的马儿,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

 

疯狂的马儿

时间限制(普通/Java) : 1000 MS/ 3000 MS          运行内存限制 : 65536 KByte
总提交 : 19            测试通过 : 5

描述

在一个5*5规模的棋盘上,放着黑马和白马。每种马都有12个,因此棋盘上恰好有一个空格。在任意时刻,马儿只允许移动到空格上(移动规则如下图所示)

 

现在,给定棋盘的初始状态,Snow_storm想知道最少移动几次可以达到如下图所示的目标状态:

 

输入

     输入的第一行为正整数T(<=100),表示测试组数。

 

     对于每组测试数据,共有5行,每行有5个字符,表示棋盘的初始状态:其中’0’表示白马,’1’表示黑马,’ ’表示空格。

 

     其中样例一对应的状态如下图所示:

输出

    对于每组测试数据,若不能在16步之内(<16)达到目标状态,则输出Crazy horse,否则输出最小步数。更多的细节请参看样例输出。

样例输入

2
01011
110 1
01110
01010
00100
10110
01 11
10111
01001
00000

样例输出

Case 1: Crazy horse
Case 2: 7

题目来源

YB


 

题目地址: http://218.194.91.48/acmhome/problemdetail.do?&method=showdetail&id=1425

原题:http://www.lightoj.com  题号1143  。。。 PS: 此题在输出时对原题做了改动。

===================================================================================================

 


 

其实只要有想法,这题的代码还是比较好实现的。

 

初步写的时候,就是用B哥说的,KM匹配作为启发式,写IDA*。

 

KM匹配只看了一点。所以让怪叔叔代敲(直接套B哥的模版)。。。

 

匹配的建图自己建,一开始对于每次匹配都重新BFS一次建图。。。

 

结果TLE在第一组测试数据。。。 于是预处理所有位置到任意位置的步数,此时匹配的建图时间就只有O(5*5*12)。。。

 

再次TLE在第二组测试数据。。。

 

一开始想了个剪枝: 不走回头路。当你往前走时,记住此时走的方向,当你在下一个位置,判断一下,不走反方向。。。

 

但是仍然TLE在第二组,貌似剪枝没效果。。。

 

只能记录状态,判断重复状态了。。。    不懂B哥记录状态的方法(貌似与后向星有关?)

 

想了一下,突然想到用字典树。。。囧。。。 时间够了,样例却过不去,13步能走的,走了15步。。。

 

然后想了一下,找到了一个BUG: DFS是深搜,也就是这个方向第5步产生的状态,也许另一个方向只需要3步就能产生。。。

 

所以状态判断不能只判断是否曾走过,还要判步数少的能再次走。。。

 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
char p[6][6];	// dfs时的当前地图 
// KM匹配 ===================================
const int maxn=33;
const int inf=0x3fffffff;
int tol,n,m,mat[maxn],lx[maxn],ly[maxn],lack,map[maxn][maxn];
bool visx[maxn],visy[maxn];
bool Find(int x){
int i,v,y;
visx[x]=true;
for(i=1;i<=n;i++){
y=i;
if(!visy[y]){
int t=lx[x]+ly[y]-map[x][y];
if(!t){
visy[y]=true;
if(mat[y]==-1||Find(mat[y])){
mat[y]=x;
return true;
}
}
else if(lack>t) lack=t;
}
}
return false;
}
int KM(){
int i,j,x,y;
/*	// 输出当前地图,与构图结果 
cout<<"p------"<<endl;
for(i=0;i<5;i++){puts(p[i]);}
cout<<"map------"<<endl;
for(i=1;i<=n;i++){for(j=1;j<=m;j++)cout<<map[i][j]<<" ";cout<<endl;}
*/
memset(mat,-1,sizeof(mat));
for(i=1;i<=n;i++){
lx[i]=-inf;
ly[i]=0;
for(j=1;j<=n;j++){
x=map[i][j];
if(x>lx[i]) lx[i]=x;
}
}
for(i=1;i<=n;i++){
while(1){
memset(visx,false,sizeof(visx));
memset(visy,false,sizeof(visy));
lack=inf;    
if(Find(i)) break;            
for(j=1;j<=n;j++){
if(visx[j]) lx[j]-=lack;
if(visy[j]) ly[j]+=lack;
}
}
}
int ret=0;
for(i=1;i<=n;i++){
if(mat[i]!=-1)
ret+=lx[mat[i]],ret+=ly[i];
}
return ret;
}
// 构图(用于KM匹配) ============ 
int fx[]={-2,2,-2,2,1,-1,1,-1};
int fy[]={-1,1,1,-1,2,-2,-2,2};
int d1[5][5]={{1,2,3,4,5},{0,6,7,8,9},{0,0,0,10,11},{0,0,0,0,12},{0,0,0,0,0}};
int d2[5][5]={{0,0,0,0,0},{12,0,0,0,0},{10,11,0,0,0},{6,7,8,9,0},{1,2,3,4,5}};
int rec[6][6][6][6];
struct Node{
int x,y;
Node(){}
Node(int a,int b){x=a,y=b;}
}que[20000];
void deal(){	// 预处理任意坐标(x1,y1)到任意坐标(x2,y2)之间的最短步数 
int i,j,vis[6][6],ss,st,cnt=1,nx,ny,k,tx,ty;
for(i=0;i<5;i++)
for(j=0;j<5;j++){
memset(vis,-1,sizeof(vis));
que[ss=st=0]=Node(i,j);
vis[i][j]=0;
while(ss<=st){
nx=que[ss].x;
ny=que[ss].y;
ss++;
if(d1[nx][ny]!=0)
rec[i][j][nx][ny]=-vis[nx][ny];
if(d2[nx][ny]!=0)
rec[i][j][nx][ny]=-vis[nx][ny];
for(k=0;k<8;k++){
tx=nx+fx[k];
ty=ny+fy[k];
if(tx<0 || ty<0 || tx>4 || ty>4) continue;
if(vis[tx][ty]!=-1) continue;
vis[tx][ty]=vis[nx][ny]+1;
st++;
que[st].x=tx;
que[st].y=ty;
}
}
cnt++;
}
}
int BFS1(){	// 匹配黑马 
int i,j,g,f,cnt=1;
for(i=0;i<5;i++)
for(j=0;j<5;j++)
if(p[i][j]=='1'){
for(g=0;g<5;g++)
for(f=(g<2?g:g+1);f<5;f++)
map[cnt][d1[g][f]]=rec[i][j][g][f];
cnt++;
}
n=12,m=12;
return KM();
}
int BFS2(){	// 匹配白马 
int i,j,g,f,cnt=1;
for(i=0;i<5;i++)
for(j=0;j<5;j++)
if(p[i][j]=='0'){
for(g=0;g<5;g++)
for(f=(g>2?g:g-1);f>=0;f--)
map[cnt][d2[g][f]]=rec[i][j][g][f];
cnt++;
}
n=12,m=12;
return KM();
}
// 字典树(用于存储状态) ================== 
struct Tree{
int step;
Tree *next[3];
};
Tree *root;
void init_(Tree *x){	// 初始化新节点 
x->step=10000;
x->next[0]=x->next[1]=x->next[2]=0;
}
int cover(int step){	// 加入字典树 
Tree *new_,*now=root;
int i,j,k,flag=0;
for(i=0;i<5;i++)
for(j=0;j<5;j++){
if(p[i][j]=='0') k=0;
else if(p[i][j]=='1') k=1;
else k=2;
if(now->next[k]==0){
new_=new Tree;
init_(new_);
now->next[k]=new_;
}
now=now->next[k];
}
if(now->step>step){	// 判断可否再走 
now->step=step;
flag=1;
}
return flag;
}
void clr(Tree *x){	// 删除字典树 (释放内存) 
if(x->next[0]) clr(x->next[0]);
if(x->next[1]) clr(x->next[1]);
if(x->next[2]) clr(x->next[2]);
delete x;
}
//  启发式搜索 ============= 
bool dfs(int x,int y,int step,int tol){
int k,h,nx,ny;
h=-(BFS1()+BFS2());	// 启发式 
if(h==0) return true;
if(h+step>tol) return false;
for(k=0;k<8;k++){
nx=x+fx[k];
ny=y+fy[k];
if(nx<0 || ny<0 || nx>4 || ny>4) continue;
swap(p[nx][ny],p[x][y]);
if(cover(step+1))	// 查询此状态是否曾走过 
if(dfs(nx,ny,step+1,tol)) return true;
swap(p[nx][ny],p[x][y]);
}
return false;
}
//  主函数 =============== 
int main(){
int tt,t,si,sj,i,j;
bool res;
char mp[6][6];
deal();
scanf("%d",&t);
getchar();
for(tt=1;tt<=t;tt++){
for(i=0;i<5;i++){
gets(mp[i]);
memcpy(p[i],mp[i],5);
for(j=0;j<5;j++)
if(mp[i][j]==' ')
si=i,sj=j;
}	
i=BFS1()+BFS2();
if(i<16)
for(i=0;i<16;i++){	// DIA*
for(j=0;j<5;j++)
memcpy(p[j],mp[j],5);
root=new Tree;	// 创建字典树 
init_(root);
cover(0);
res=dfs(si,sj,0,i);
clr(root);
if(res) break;
}
printf("Case %d: ",tt);
if(i<16) printf("%d\n",i);
else puts("Crazy horse");
}
return 0;
}
/*
1
00111
01111
11111
00 00
00000
*/


 

这篇关于SWUN 1425 - 疯狂的马儿的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/663358

相关文章

YoloV10改进策略:下采样改进|自研下采样模块(独家改进)|疯狂涨点|附结构图

文章目录 摘要自研下采样模块及其变种第一种改进方法 YoloV10官方测试结果改进方法测试结果总结 摘要 本文介绍我自研的下采样模块。本次改进的下采样模块是一种通用的改进方法,你可以用分类任务的主干网络中,也可以用在分割和超分的任务中。已经有粉丝用来改进ConvNext模型,取得了非常好的效果,配合一些其他的改进,发一篇CVPR、ECCV之类的顶会完全没有问题。 本次我将这个模

当电商“邂逅”微信支付 比想象还疯狂

微信支付在为移动电商带来高效解决方案的同时,也促进了新的移动电商生态的形成。” 12月6日,在腾讯“当电商‘邂逅’移动支付”把脉沙龙上,微信团队与电商代表、外部专家就 微信支付与电商的现状和前景展开研讨,指出当前的“微信价”现象代表了电商企业对微信支付商业模式的探索。未来,微信支付有望发展成为移动互联网时代的一项基础能力,其与微信平台的紧密结合,将帮助电商企业构建起移动互联网时代的全新商业生态。

P1616 疯狂的采药(完全背包模板)

//这是一道完全背包的题,并且需要用一维数组优化空间,否则会MLE #include <bits/stdc++.h>using namespace std;//t表示可以用来采药的时间(相当于背包容量)//m表示草药的数目(相当于物品数量)int t, m; //m<=10^4,t<=10^7 //w[i]表示采摘第i种草药需要花费的时间(相当于背包模型中物品的体积) //v[i]

到处在裁员,这个行业却在疯狂招人!

1.裁员浪潮不断 8月26日,IBM中国方面确认了将关闭中国研发部门的消息,这一决策涉及员工数量超过1000人。技术迭代浪潮前,哪怕是名企,攻守防退之间的转换也只在一瞬间。AI引发大裁员?这表明IBM正在积极适应技术变革,以提高效率和竞争力,被裁的员工该何去何从? 近期大家也发现,京东开始抓考勤,要减少午休时间一个小时,六点半下班需要提前申请,以提高效率和竞争力。前几年互联网相关的投资非常

又是一个疯狂的程序

// 这个程序路径:D:\fc.cpp#include <iostream>#include <cstdio>#include <cstdlib>using namespace std;int main(){int x;scanf("%d", &x);while(x --){system("start D:\\fc.cpp");system("D:\\fc.cpp start");}re

笨鸟先飞(疯狂的小鸟)小游戏自制分享

《Flappy Bird》是一款由越南独立游戏开发者阮哈东(Dong Nguyen)制作并发布的移动端小游戏。该游戏最初于2013年上线,在2014年初迅速走红,成为全球范围内的热门现象。 游戏的玩法非常简单,玩家只需通过点击屏幕来控制一只小鸟飞行,避开不断出现的绿色管道。每点击一次,鸟儿会上升一点,不点击则会下降,玩家的目标是尽量通过更多的管道而不碰撞障碍物。虽然看似容易,但由于操作精准度要

警告,恶意域名疯狂外联,原因竟然是……

前言 &nbsp;&nbsp; 在某个风和日丽的下午,突然收到客户那边运维发过来的消息说我司的DTA设备在疯狂告警,说存在恶意域名外联,我急忙背上小背包前往客户现场,经过与客户协同排查,最终确定该事件为一起挖矿病毒引起的恶意域名外联事件。(因客户信息保密且为了保证文章逻辑完整性,部分截图为后期追加图) 事件分析 一看域名地址donate.v2.xmrig.com

超详细!想进华为od的请疯狂看我!

三分钟带你全面了解华为OD 【合同及管理】签约方为科锐国际/外企德科(人力服务公司),劳动合同期为4年,试用期6个月。员工关系合同管理、五险一金、考勤发薪由科锐国际/外企德科负责;定级定薪、员工培训、工作安排、绩效评比和晋升等由华为负责。 【薪酬福利薪资结构】 ① 基本工资+绩效工资+年终奖(2-4个月,一般绩效A-4个月,B-2个月);② D1-D5分别对应华为13-17级,参考范围10-

疯狂刷题python版 | 使用PySide6自制刷题软件【源码+解析】

疯狂刷题python版 | 使用PySide6自制刷题软件【源码+解析】 一、前言二、思考三、软件设计四、软件实现(一)使用QWebEngineView控件通过JavaScript代码和chrome内核进行数据交互和逻辑控制(二)用户分别通过浏览器 GUI和PySide6 GUI进行操作(三)使用PySide6 GUI获取用户计算机本地资源 五、遇到问题及解决方案(一)如何把excel数据转

MySQL从放弃到疯狂

SQL基础 InnoDB存储引擎 存储引擎常用的命令 show engines; # 查看所支持的所有存储引擎show variables like '%storage_engine%'; # 查看默认的存储引擎SET DEFAULT_STORAGE_ENGINE=MyISAM; # 设置默认存储引擎#创建表时指定存储引擎create table tableNmae{...}engi