您的位置:首页 > 编程语言 > C语言/C++

2016蓝桥杯C/C++省赛 剪邮票(深搜DFS+暴力)

2017-03-21 12:03 246 查看
题目:



思路:

先枚举一下组合数,也就是C(12,5)=792种可能,然后判断每一种可能是否连通,那怎么判连通呢?因为我的num[1]~num[5]存储的是那五个数,所以我们判断如果从num[1]能走到num[2]~num[5]中的任意一个点的话,就证明这一片区域是连通的,用一个flag变量来记录从num[1]走到其他点成功的次数,总共有四种可能(1~2,1~3,1~4,1~5),如果都能走到的话,那么flag的值应该是4,这样的话就证明连通一个去区域了,所以就把cntt++,最后输出cntt的值就行,(x1,y1)代表的是起始点的坐标,(x2,y2)代表终点的坐标,注意实时更新,感觉时间复杂度有点高,但是才跑了0.033s...

代码:

#include <stdio.h>
#include <string.h>
#include <string>
#include <iostream>
#include <stack>
#include <queue>
#include <vector>
#include <algorithm>
#define mem(a,b) memset(a,b,sizeof(a))
#define inf 0x3f3f3f3f
#define N 1000+10
#define LL long long
using namespace std;
int num[10],cntt=0,flag;
int vis[10][10];
int go[4][2]={1,0,-1,0,0,1,0,-1};
int x2,y2;
int judge(int x,int y)//判断这个点是否在这五个点内
{
int k=4*(x-1)+y;//坐标转换成数字
for(int i=1;i<=5;i++)
{
if(k==num[i])
return 1;
}
return 0;
}
void dfs(int x1,int y1)
{
if(x1==x2&&y1==y2)
{
flag++;
return;
}
for(int i=0; i<4; i++)
{
int xx=x1+go[i][0];
int yy=y1+go[i][1];
if(xx>=1&&xx<=3&&yy>=1&&yy<
4000
=4&&vis[xx][yy]==0&&judge(xx,yy))
{
vis[xx][yy]=1;
dfs(xx,yy);
}
}
}
void init(int nn,int mm)
{
int i;
if(mm==0)//当mm==0时,num[1]~num[5]中存储的就是枚举的这五个数
{
flag=0;//初始化flag
int x1=(num[1]-1)/4+1;//把数值num[1]转换成坐标的形式
int y1=(num[1]-1)%4+1;
for(int i=2; i<=5; i++)//搜索从num[1]分别走到num[2]~num[5],如果都可以走到的话,证明这一片区域是连通的
{
x2=(num[i]-1)/4+1;//转换成坐标
y2=(num[i]-1)%4+1;
mem(vis,0);//标记数组清零
vis[x1][y1]=1;//标记当前点
dfs(x1,y1);//从起点开始搜索
}
if(flag==4)//一共有四种可能,如果都能走得通,就证明这一片区域连通
cntt++;
return;
}
for(int i=nn; i>=mm; i--)//枚举组合数
{
num[mm]=i;
init(i-1,mm-1);
}
}
int main()
{
init(12,5);//枚举组合数,在12个数中选5个数的组合
cout<<cntt<<endl;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: