2016第七届蓝桥杯C++ A组 剪邮票(全排列+DFS)

不得不说蓝桥杯对全排列是情有独钟啊,一年考了三个全排列…
如【图1.jpg】, 有12张连在一起的12生肖的邮票。
现在你要从中剪下5张来,要求必须是连着的。
(仅仅连接一个角不算相连)
比如,【图2.jpg】,【图3.jpg】中,粉红色所示部分就是合格的剪取。
在这里插入图片描述
请你计算,一共有多少种不同的剪取方法。

注意此题不能直接用DFS做(我就直接做的 ),不能做的原因是DFS不能处理"T"型,DFS只能在四个方向中选择一个走,不能同时走左和右多个方向。这样如图3的情况便不会得到。
在这里插入图片描述
其实暴力就完事了,暴力求解出12个块里边任选五个块,再用DFS求连通块的方法看这五个块是否连通,如果连通则此法符合题意。
那么该如何12个里选5个呢?
要把所有的组合情况都考虑到,当然首选全排列啦,设置一个num数组,把选择此块记为1,不选记为0,然后对数组全排列即可。全排列后注意把num数组转化为地图的二维数组再去求连通块。
代码如下

#include <iostream>
#include <string>
#include <set>
#include <vector>
#include <algorithm>


int mp[3][4];
int dir[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
int vis[3][4];
int cnt;
int ans;
void dfs(int x,int y)//求连通块
{
    if(x>2 || y>3 || x<0 || y<0 ) return;
    if(mp[x][y]!=1 )return;
    cnt ++;//连通的数目加一
    if(cnt == 5)//如果连通的块数为5说明选择的五个点是连通的
    {
        ans++;
        return;
    }
    mp[x][y] = 0;//此点连通后就标为0
    for(int i=0;i<4;i++)
    {
        int dx = x+dir[i][0];
        int dy = y+dir[i][1];
        dfs(dx,dy);
    }
}
int main()
{
    int px,py;
    int num []= {0,0,0,0,0,0,0,1,1,1,1,1};//通过全排列方式得到12个里选5个的选法
    do
    {
        for(int i=0;i<3;i++)
        {
            for(int j=0;j<4;j++)
            {
                if(num[i*4+j]==1)//把num数组为1即代表选择此点,转化为二维数组体现
                {
                   px = i;//随便记录为1的一点,以这点开始连通块的搜索
                   py = j;
                   mp[i][j] = 1;
                }
                else
                    mp[i][j] = 0;
            }
        }
       dfs(px,py);//连通块搜索
       cnt = 0;//搜索后数量记录置零
    }while(next_permutation(num,num+12));
    cout<<ans;
}

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
DESCRIPTION: 1.Analyze Problem A : sorted stamps array A={ai} ai: one stamp element in array n: array size, that is number of elements in array r: desired value of stamps F(n,r):expected result, minimum number of stamps for a given value r from n size array. S: selected stamps array S={si} 2.Choose Algorithm a.Greedy algorithm seems to be a good choice, try to solve it in O(n), i try divide array into subarry B={bi}, r should larger than every elemnt in B that is r>bi and suppose bk is the smallest element in B, so that r= bk%r, f(i,r)=(bk/r), F(n,r)=∑f(i,r). The main idea is to choose the last element who larger than desired value each time. However,it can not give us optimal solution in some condition, like A={8,5,4,1}, if r=10, this algoritm will give a solution F(n,r)=3, S={8,1,1},but the optimal solution should be F(n,r)=2, S={5,5}. b.Full search so the straight forwards algorithm is to search for every solution in A for desired value directly.However, it will always take O(n!) to go through every combination. c.Dynamic programming, at last, I decide to choose dynamic programming. analyze optimal structure, suppose in A={ai}, for a specific stamp ak,there will be two cases it is choosen so that f(i,r)=1+f(i,r-ak) , 1<=i<=k, r>=ak it is not valid so that f(i,r)=f(i-1,r) 3.Design Dynamic programming optimal structure: Compute-opt(r)= 1 + Compute-opt(r-ai) value: Compute-opt(r) = ∞ (r < 0) Compute-opt(r) = 0 (r = 0) Compute-opt(r) = 1+{Compute-opt(r-ai)} ( 1=<i<=n, r>ai>0 ) Complexity :O(nr) Memory cost:O(n+r) Compute in a bottom-up style to recursive every desired value and array. store value of Compute-opt in memory for future use, so that we can easily get value from those memory in future recursive call, and avoid compute again, that is if the array is not change, you can easily fetch result any desired value j (j < r, r is the value using for compute ). 2.For User totally, I design a small command line for this machine list below 1.Manual Operation 2.Self Auto Testing 3.Check Results q.Quit Manual Operation: when select this machine will turn to be manual mode, ask person to input stamps and desired value; Self Auto Testing:when select this machine will turn to be auto mode, show the test case already design in code after that machine will quit automatically. Check Results: only be visiable in Manual Operation, people can check desired value for the array input before, the desired value should be no more than first time input. Quit, clean all the memory and quit system.

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值