2016年第七届蓝桥杯【C++省赛B组】【第七题:剪邮票】——并查集

标题:剪邮票

如【图1.jpg】, 有12张连在一起的12生肖的邮票。


现在你要从中剪下5张来,要求必须是连着的。
(仅仅连接一个角不算相连)

比如,【图2.jpg】,【图3.jpg】中,粉红色所示部分就是合格的剪取。



请你计算,一共有多少种不同的剪取方法。

请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。


看到很多用搜索的,想了想,并查集也能做,相邻也就是连在一起了。

先用一个结构体记录每个格子的编号、坐标、是否被选,然后选出五个格子,计算这五个格子有多少个独立分块,如果只有一个,说明是连着的,属于一种方案。

代码:

#include<bits/stdc++.h>
using namespace std;
int pre[12];
struct youpiap {
  int x, y, flag;
}p[12];
int find(int x) {
  if(x == pre[x]) return x;
  return pre[x] = find(pre[x]);
}
void join(int n) {
  int xx = p[n].x, yy = p[n].y;
  int father = find(n);
  for(int i = 0; i < 12; i++) {
    if(i == n || p[i].flag == 0) continue;
    if((p[i].x==xx&&p[i].y==yy+1) || (p[i].x==xx&&p[i].y==yy-1) || (p[i].x==xx+1&&p[i].y==yy) || (p[i].x==xx-1&&p[i].y==yy)) {
      pre[find(i)] = father;
    } 
  } 
}
int main() {
  int sum = 0;
  for(int i = 0; i < 12; i++) {
    pre[i] = i;
    p[i].flag = 0;
  }
  int kk = 0;
  for(int i = 1; i <= 3; i++)
    for(int j = 1; j <= 4; j++) {
      p[kk].x = i;
      p[kk].y = j;
      kk++;
    }
  for(int i = 0; i < 8; i++) {
    for(int j = i+1; j < 9; j++) {
      for(int k = j+1; k < 10; k++) { 
        for(int q = k+1; q < 11; q++) {
          for(int t = q+1; t < 12; t++) {
            p[i].flag = 1, p[j].flag = 1, p[k].flag = 1, p[q].flag = 1, p[t].flag = 1;
            for(int i = 0; i < 12; i++)
              if(p[i].flag) join(i);
            set<int> s;
            for(int i = 0; i < 12; i++)
              if(p[i].flag) s.insert(find(i));
            if(s.size() == 1) sum++;
            for(int tt = 0; tt < 12; tt++)
              pre[tt] = tt;
            p[i].flag = 0, p[j].flag = 0, p[k].flag = 0, p[q].flag = 0, p[t].flag = 0;
          }   
        }      
      } 
    }  
  }
  cout << sum << endl;
  return 0;
}


阅读更多
个人分类: 蓝桥杯
上一篇2018年第九届蓝桥杯【C++省赛B组】【第十题:乘积最大】——贪心算法
下一篇2016年第七届蓝桥杯【C++决赛赛B组】【第二题:凑平方数】——全排列+暴力DFS
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭