漫游小镇 解题报告
来源:互联网 发布:大闹天宫瑰羽进阶数据 编辑:程序博客网 时间:2024/06/09 20:01
漫游小镇
一个正方形的镇区分为 N2 个小方块(1<= N <= 7)。农场位于方格的左上角,集市位于左下角。贝茜穿过小镇,从左上角走到左下角,刚好经过每个方格一次。当 N=3 时,贝茜的漫游路径可能如下图所示:
写一个程序,对于给出的 N 值,计算贝茜从农场走到集市有多少种唯一的路径。
PROGRAMNAME: betsy
INPUTFORMAT
行 1: 一个整数N (1 <= N <= 7)
SAMPLEINPUT (file betsy.in)
3
OUTPUTFORMAT
只有一行。输出一个整数表示唯一路径的数量。
SAMPLEOUTPUT (file betsy.out)
2
这道题暴搜是过不了的,,不过考试的时候用了大概十分钟吧写出来,,然后让它跑完了打表。。。
虽然有点不怀好意,但是为我节省了不少时间呢。。
【代码】(不要理打表,,其实我的搜索是对的,,只不过时间有点长。。)
#include<iostream>#include<cstdio>#include<cstring>using namespace std;//int sx[4]={1,-1,0,0};//int sy[4]={0,0,1,-1};int n,ans;//int a[100][100];int b[100];/*void dfs(int s,int t,int dep){int r,x,y;if (s==n&&t==1){if (dep==n*n) ans++;return;}for (r=0;r<4;++r){x=s+sx[r];y=t+sy[r];if (x>0&&y>0&&x<=n&&y<=n&&a[x][y]==0){a[x][y]=1;dfs(x,y,dep+1);a[x][y]=0;}}}*/int main(){freopen("betsy.in","r",stdin);freopen("betsy.out","w",stdout);scanf("%d",&n);//a[1][1]=1;//dfs(1,1,1);//printf("%d",ans);b[1]=1; b[2]=1; b[3]=2; b[4]=8; b[5]=86; b[6]=1770; b[7]=88418;printf("%d",b[n]);return 0;}
好吧来说说正解(摘自nocow题解):
搜索
这道题要使用DFS加上优化才可以过。朴素的搜索只能解决到N=5,6会超时。于是要加上一些优化。
优化1
不走死胡同!所谓死胡同,就是走进去以后就再也无法走出来的点。
一种简单的想法是:任意时刻,必须保证和当前所在位置不相邻的未经点至少有两个相邻的未经点。基于这种想法,可以采取这样的优化:
当前点周围的点D,如果只有一个与D相邻的未经点,则点D为必经点。
显然,如果当前点周围有两个或两个以上的符合上述条件的必经点,则无论走哪个必经点都会造成一个死胡同,需要剪枝。
如果当前点周围只有一个必经点,则一定要走到这个点。
如果该点周围没有必经点,则需要枚举周围每一个点。
该优化的力度很大,可以在0.2秒内解决N=6,但N=7仍然需要2秒左右的时间。
优化2
不要形成孤立的区域。如果行走过程中把路一分为二,那么肯定有一部分再也走不到了,需要剪枝。
形成孤立的区域的情况很多,如果使用Floodfill找连通快,代价会很大,反而会更慢。我只考虑了一种最容易出现特殊情况,即:
当前点左右都是已经点(包括边缘),而上下都是未经点;
当前点上下都是已经点(包括边缘),而左右都是未经点。
这样就会形成孤立的区域,只要将出现这种情况的状态都剪掉即可。
加上优化2,N=7也能在0.3s解决了。
【代码】(依然是找的标算,不过是pascal的,自己打了一遍,基本都看懂了,,加了点注释)#include<iostream>#include<cstdio>#include<cstring>using namespace std;int dx[5]={0,1,0,0,-1};int dy[5]={0,0,1,-1,0};bool map[9][9];int n,nn,i,sum;bool ok(int x,int y)//优化2,判断是否会形成孤立的区域 {int i,j;if (map[x+1][y]==true&&map[x-1][y]==true&&map[x][y+1]==false&&map[x][y-1]==false) return false;if (map[x+1][y]==false&&map[x-1][y]==false&&map[x][y+1]==true&&map[x][y-1]==true) return false;return true;} int get(int x,int y)//优化1,return点(x,y)周围有几个未经点 { int c,i; c=0; for (i=1;i<=4;++i) if (!map[x+dx[i]][y+dy[i]]) c++; return c; }void dfs(int x,int y,int step){int i,j,c,tx,ty;if (x==n&&y==1) {if (step==nn) sum++;return;}if (step==nn) return;c=0;//优化1,开始寻找“必经点” for (i=1;i<=4;++i) if (!map[x+dx[i]][y+dy[i]]) { if (get(x+dx[i],y+dy[i])<=1) { c++; tx=x+dx[i]; ty=y+dy[i]; if (tx==n&&ty==1) c--; if (c>1) break; } }if (c>1) return;//优化1,剪枝 if (c==1)//优化1,如果只有一个必经点,则一定要走这个点 {map[tx][ty]=true;dfs(tx,ty,step+1);map[tx][ty]=false;return;} for (i=1;i<=4;++i)//优化1,否则枚举周围的每一个点 if (!map[x+dx[i]][y+dy[i]]&&ok(x+dx[i],y+dy[i])) { map[x+dx[i]][y+dy[i]]=true; dfs(x+dx[i],y+dy[i],step+1); map[x+dx[i]][y+dy[i]]=false; }}int main(){scanf("%d",&n);for (i=0;i<=n+1;++i){map[i][0]=true;//将边界值都赋为true,有效地防止越界 map[i][n+1]=true;map[0][i]=true;map[n+1][i]=true;}nn=n*n;map[1][1]=true;dfs(1,1,1);printf("%d",sum);return 0;}【心得】
朴素的搜索+小聪明有时候是非常必要的,,但是厉害的优化一定要学。。考试时是不择手段的拿分,,但是过后要学一学正解,,不能保证以后这样的题会不会再遇到。。。
会做才是硬道理,骗分的最高境界就是不骗分。——《骗分导论》
- 漫游小镇 解题报告
- ?|USACO 5.4.4|Betsy's Tour|漫游小镇|插头DP
- 【USACO题库】5.4.4 Betsy's Tour漫游小镇
- 解题报告
- 解题报告
- 解题报告
- 解题报告
- 解题报告
- 解题报告
- 解题报告
- 漫游
- 漫游
- 漫游
- 漫游
- 漫游
- Antiprime解题报告
- expr解题报告
- 华容道解题报告
- WPF入门(八)布局(layout) port 2
- java实现文件的上传和下载
- android开发(1) - 登录界面的布局演示
- android开发(1) - 登录界面的布局演示
- SDN和NFV的基础,Intel如何思考
- 漫游小镇 解题报告
- android开发(2) - 九宫格的实现
- 【Game】protobuf:windows下环境配置
- android开发(3) 可滚动的录入表单演示
- android开发(4) 闪屏的实现
- android开发(5) 动态生成控件
- HDU 1075 What Are You Talking About(字典树模板题)
- android开发(6) - 初遇handler
- POJ 1094 Sorting It All Out (拓扑排序)