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

本文通过枚举组合数的方法探讨如何判断一组特定坐标点是否构成连通区域的问题。利用深度优先搜索(DFS)策略,验证从一个起始点出发能否到达其余所有指定目标点,以此确定这些点是否形成一个连通的集合。

题目:


思路:

先枚举一下组合数,也就是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<=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;
}



评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值