剪格子

题目描述
如图p1.jpg所示,3 x 3 的格子中填写了一些整数。

我们沿着图中的红色线剪开,得到两个部分,每个部分的数字和都是60。

本题的要求就是请你编程判定:对给定的m x n 的格子中的整数,是否可以分割为两个部分,使得这两个区域的数字和相等。
如果存在多种解答,请输出包含左上角格子的那个区域包含的格子的最小数目。
如果无法分割,则输出 0

程序输入输出格式要求:
程序先读入两个整数 m n 用空格分割 (m,n<10)
表示表格的宽度和高度
接下来是n行,每行m个正整数,用空格分开。每个整数不大于10000
程序输出:在所有解中,包含左上角的分割区可能包含的最小的格子数目。

例如:
用户输入:
3 3
10 1 52
20 30 1
1 2 3

则程序输出:
3

再例如:
用户输入:
4 3
1 1 1 1
1 30 80 2
1 1 1 100

则程序输出:
10

(参见p2.jpg)

资源约定:
峰值内存消耗(含虚拟机) < 64M
CPU消耗 < 5000ms

请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。

所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意:不要使用package语句。不要使用jdk1.6及以上版本的特性。
注意:主类的名字必须是:Main,否则按无效代码处理。

import java.util.HashMap;
import java.util.HashSet;
import java.util.Scanner;
import java.util.Stack;/**在蓝桥杯的测试里能AC* 主要思想分成3部分:*     1.统计矩阵里所有的数值的情况(这里用TreeMap可能会更好),搜索一个序列,这个序列加起来等于(总和/2 - 左上角的数),即这个序列加左上角的数等于总和的一半*     2.从左上角开始遍历,测试1得到的数据能不能拼接到一个相连的块中*     3.测试2得到的结果是不是正好将矩阵分成了两部分* 采取1的原因在于直接遍历的计算量很大,实际是可能超时的,也可以进行记忆优化,我想大概可以使用HashMap<当前的和, 计算过与否>[10][10]作为搜索的记录* 步骤1、2都有缺点,都能进一步优化,都能记忆处理**/
public class Main {static final int MAX  = 10005; // 输入值得最大值static final int MLEN = 105;   // 输入矩阵的最大数据个数static int m, n;static int[] nums;static int[] hash;static int aim;public static void main(String[] args) throws Exception {Scanner sc = new Scanner(System.in);m = sc.nextInt();n = sc.nextInt();nums = new int[n * m];hash = new int[MAX]; // 散列uf = new int[m * n]; // 类似并查集,最后判断是否分割成两部分使用int all = 0;  // 总和for(int i = 0; i < nums.length; i ++) {int t = sc.nextInt();nums[i] = t;hash[t] ++;all += t;}sc.close();hash[nums[0]] --; // 将位置0从中删除if(all % 2 != 0) { // 和为奇数System.out.println(0);return;}aim = all / 2 - nums[0];findAim(0, MAX-1);if(!find)System.out.println(0);}static int[] list = new int[105]; // 当前已经选择的数值static int ind = 0; // 列表当前的下标static boolean find = false; // 当找到了一个合理的答案之后,程序能快速结束public static void findAim(  // 查找一个能满足和为aim的序列int sum,             // 当前的和int index) {         // 遍历的位置if(find)return;if(sum > aim)return;if(sum == aim) {if(isValid()) {System.out.println(ind + 1);find = true;}return;}while(index > 0) {if(hash[index] > 0) {for(int i = hash[index]; i > -1; i --) {    // 加上n个index的值 贪心为上for(int j = 0; j < i; j ++) {           // 更新链表list[ind ++] = index;}findAim(sum + i*index, index-1);ind -= i;  // 回溯}return;}else {index --;}}}// 判断当前的list是否合法// 需要判断//   1.是否能将list数据和arr[0]拼接成一个整体//   2.判断生成的结果是否可以分成两部分static boolean isValid() {validIndex = new HashSet<Integer>();validIndex.add(1);validIndex.add(m);exist[0] = true; // 已经拥有0,0点// 将list散列化 由于每一次都建立一个MAX大小的向量是不现实的,使用Map结构记录tempMap.clear();for(int i = 0; i < ind; i ++) {Integer old = tempMap.put(list[i], 1);     // 当前能够加入的值if(old != null)tempMap.put(list[i], 1 + old);}return dp(0);}static HashSet<Integer> validIndex;static HashMap<Integer, Integer> tempMap = new HashMap<Integer,Integer>(); // 记录list中需要的数据,以及其需要的次数static boolean[] exist = new boolean[MLEN]; // 当前已经拥有的位置static boolean dp(int count) {if(count == ind) {if(isTwoPart())return true;elsereturn false;}// 找到当前能加入的点// 结束时,addStack中包含了当前能加入的点的位置// addStack里面放的是能加入的位置Stack<Integer> addStack = new Stack<Integer>();for(int li:validIndex) {      // 遍历当前的合法位置Integer key = tempMap.get(nums[li]);if(key != null && key != 0) {addStack.add(li);}}// 选定一个点,加入while(!addStack.isEmpty()) {int node = addStack.pop();int type = addNode(node);if(dp(count + 1))return true;removeNode(node, type);}return false;}public static int addNode(int node) { // 加入一个位置,返回变动的类型int type = 0;if((node+1)%m != 0   && !exist[node + 1])        // 如果没到行末if(validIndex.add(node + 1)) type |= 1;if((node+m)   <  m*n && !exist[node + m])        // 如果没到列末if(validIndex.add(node + m)) type |= 2;if((node-m)   >  0   && !exist[node - m])        // 不是第一行if(validIndex.add(node - m)) type |= 4;if(node % m   != 0   && !exist[node - 1])        // 不是第一列if(validIndex.add(node - 1)) type |= 8;validIndex.remove(node); // 删除自身exist[node] = true;tempMap.put(nums[node], tempMap.get(nums[node]) - 1);   // 维护mapreturn type;}public static void removeNode(int node, int type) {if((type & 1) != 0) validIndex.remove(node + 1);if((type & 2) != 0) validIndex.remove(node + m);if((type & 4) != 0) validIndex.remove(node - m);if((type & 8) != 0) validIndex.remove(node - 1);validIndex.add(node);exist[node] = false;tempMap.put(nums[node], tempMap.get(nums[node]) + 1);   // 维护map}static int[] uf; // 类似并查集Union Find// 判断是否真的将表格分成两个部分public static boolean isTwoPart() {for(int i = 0; i < uf.length; i ++){uf[i] = -1;}// 由于nums[0]一定是被选上的,故,先统计从nums[0]开始能合并多少个节点uf[0] = 1;merge(0);// 找到一个没有被选择的位置,合并int index = 0;for(int i = 1; i < exist.length; i ++) {if(!exist[i]) {index = i;break;}}uf[index] = 2;merge(index);// 经过上述两个合并,使uf中最起码存在两个集合,这两个集合是联通的,且一个被选取的,一个不被选取的// 如果uf还存在-1,就说明存在不能被两个集合划分for(int i = 0; i < uf.length; i ++) {if(uf[i] == -1)return false;}return true;}// 从index位置开始,将与其相连且标签(标签指是否是否被选取)与其一致的元素合并,考虑exist数组public static void merge(int index) { if((index+1)%m != 0    && exist[index] == exist[index+1]) check(index, index + 1);// 如果没到行末,并且行末和这个位置的标签一致if((index+m)   <  m*n  && exist[index] == exist[index+m]) check(index, index + m);if((index-m)   >  0    && exist[index] == exist[index-m]) check(index, index - m);if(index % m   != 0    && exist[index] == exist[index-1]) check(index, index - 1);}// 为了能简单merge的代码,抽取代码// 实际作用是:在已经判明index和next都存在,并且两者标签相同时,应该进行怎样的操作public static void check(int index, int next) {if(uf[next] == uf[index])  // 说明是重复搜索return;else {uf[next] = uf[index];merge(next);           // 对next进行搜索}}}

java实现第四届蓝桥杯剪格子相关推荐

  1. java实现第四届蓝桥杯公式求值

    公式求值 输入n, m, k,输出图1所示的公式的值.其中C_n^m是组合数,表示在n个人的集合中选出m个人组成一个集合的方案数.组合数的计算公式如图2所示. 输入的第一行包含一个整数n:第二行包含一 ...

  2. java实现第四届蓝桥杯核桃的数量

    核桃的数量 题目描述 小张是软件项目经理,他带领3个开发组.工期紧,今天都在加班呢.为鼓舞士气,小张打算给每个组发一袋核桃(据传言能补脑).他的要求是: 各组的核桃数量必须相同 各组内必须能平分核桃( ...

  3. java实现第四届蓝桥杯危险系数

    危险系数 抗日战争时期,冀中平原的地道战曾发挥重要作用. 地道的多个站点间有通道连接,形成了庞大的网络.但也有隐患,当敌人发现了某个站点后,其它站点间可能因此会失去联系. 我们来定义一个危险系数DF( ...

  4. java实现第四届蓝桥杯振兴中华

    振兴中华 题目描述 小明参加了学校的趣味运动会,其中的一个项目是:跳格子. 地上画着一些格子,每个格子里写一个字,如下所示:(也可参见p1.jpg) 从我做起振 我做起振兴 做起振兴中 起振兴中华 比 ...

  5. java实现第四届蓝桥杯大臣的旅费

    大臣的旅费 题目描述 很久以前,T王国空前繁荣.为了更好地管理国家,王国修建了大量的快速路,用于连接首都和王国内的各大城市. 为节省经费,T国的大臣们经过思考,制定了一套优秀的修建方案,使得任何一个大 ...

  6. java实现第四届蓝桥杯好好学习

    好好学习 汤姆跟爷爷来中国旅游.一天,他帮助中国的小朋友贴标语.他负责贴的标语是分别写在四块红纸上的四个大字:"好.好.学.习".但是汤姆不认识汉字,他就想胡乱地贴成一行. 请你替 ...

  7. java实现第四届蓝桥杯猜灯谜

    猜灯谜 题目描述 A 村的元宵节灯会上有一迷题: 请猜谜 * 请猜谜 = 请边赏灯边猜 小明想,一定是每个汉字代表一个数字,不同的汉字代表不同的数字. 请你用计算机按小明的思路算一下,然后提交&quo ...

  8. java实现第四届蓝桥杯有理数类

    有理数类 题目描述有理数就是可以表示为两个整数的比值的数字.一般情况下,我们用近似的小数表示.但有些时候,不允许出现误差,必须用两个整数来表示一个有理数.这时,我们可以建立一个"有理数类&q ...

  9. 金蝉素数c语言,算法笔记_204:第四届蓝桥杯软件类决赛真题(Java语言C组)

    前言:以下代码仅供参考,若有错误欢迎指正哦~ 1好好学习 汤姆跟爷爷来中国旅游.一天,他帮助中国的小朋友贴标语.他负责贴的标语是分别写在四块红纸上的四个大字:"好.好.学.习".但 ...

最新文章

  1. 转载:Objective-C中的 instancetype 和 id 关键字
  2. access和SQL的区别
  3. leetcode C++ 25. K 个一组翻转链表 给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。
  4. android 11微信,QQ,支付宝无法调用的问题
  5. 1092. To Buy or Not to Buy (20)
  6. labuladong 的算法小抄_来自GitHub 68.8k star的硬核算法教程
  7. 百练 04 简单的整数划分问题
  8. 快充线与普通线的区别_四种不同线身材质对比:iPhone12首次标配编织线或将引领潮流?...
  9. 整个线上营销_而言,最重要的是什么?
  10. 用户控件页为什么找不到.ClientScript.RegisterClientScriptBlock原因
  11. k-近邻算法 ---sklearn
  12. 中国移动智能网关(光猫)超级管理员账户密码 型号: PT924G
  13. Multisim实现D触发器模拟异步计数器
  14. Netplus收发消息的基本流程
  15. 大鹏教你python数据分析
  16. 90后姑娘因熬夜长出老年斑吓坏网友!拯救熬夜党,智能家居也能出份力?
  17. linux离线安装jemalloc,jemalloc在linux上从安装到使用
  18. Web开发之-CS架构与BS架构
  19. JSP+structs图书管理系统
  20. MATLAB路面裂缝检测识别算法仿真

热门文章

  1. 如何用蓝牙网关广播蓝牙数据
  2. 用Python学《微积分B》(Taylor公式与曲线拟合)
  3. T9632 待机led 控制
  4. 利用Linux的crontab实现定时执行python任务
  5. 专业范儿的图表,打造专业范儿的技术人PPT
  6. HTML+CSS实战(哈罗单车首页)
  7. Win10如何用命令打开控制面板
  8. 【 react】react实现页面后退按钮(goBack())
  9. python len()函数的用法
  10. 局域网共享文件夹/共享文件夹无法访问解决办法