挑战 渣打科营“Mini Code Marathon”赛题:连通块最少

来源:互联网 发布:比特币技术指标软件 编辑:程序博客网 时间:2024/05/22 07:09
package csdn;


/**


 * 渣打科营“Mini Code Marathon”赛题:连通块最少


 * @author Cheeps


 * 思路:在同一个全1连通块中,任何两个1的最小距离等于他们下标的距离减一,即任何两个1之间的路径,


 * 在只能往前走,不能往后退,无论纵向或横向,一旦有回退的步骤,最小距离必然会大于他们下标的距离减一


 * 故而要保证任何两个1的最小距离等于他们下标的距离减一就是要保证任何同行或同列的1之间没有0


 * 那么一旦同行或同列中两个1之间有0把这些0变成1即可达到题目要求


 * 主要方法:getConnectedOnes(n,m)每次得到一个全1连通子图


 *  countChanges(n,m)得到一个全1连通子图变合法需要改变的0的个数


 * 操作流程:根据提示输入01矩阵的行、列,用户输入01矩阵后,程序先打印出该矩阵合法的连通矩阵,根据用户的选择输入下一组测试数据或输出结果


 */


public class ConnectedOnes {





static int[][]metric = new int[50][50];//01矩阵


static int ones = 0;//记录整个01矩阵中1的个数,每次找到一个连通子图时把这个子图包含的所有1全部变为2,ones也相应减少,当ones重新为0时01矩阵也就合法了





/**


* 得到01矩阵中的全1连通块数组,得到的signal数组中标记为1的为一个全1连通块


* 核心:遍历矩阵,遇到的第一个1,令它属于连通子图,是否为第一个1用start来标示


* 对于以后遇到的每个1,如果它的左、上方元素中有一个属于连通子图,则这个1也属于连通子图


* @param n


* @param m


* @return signal


*/


private static int[][] getConnectedOnes(int n,int m){


boolean start = true;//判断是否为连通图的开始


int[][]signal = new int[n][m];//标记连通图包含的点


for(int i = 0;i < n;i++){


for(int j = 0;j < m;j++){


if(start && metric[i][j] == 1) {


signal[i][j] = 1;


metric[i][j] = 2;


ones--;


start = false;


}


else if(metric[i][j] == 1){//如果当前元素为1且左、上两个元素属于连通子图,则当前点是否属于连通子图


if(i > 0 && signal[i - 1][j] == 1) {


signal[i][j] = 1;


metric[i][j] = 2;


ones--;


}


if(j > 0 && signal[i][j - 1] == 1) {


signal[i][j] = 1;


metric[i][j] = 2;


ones--;


}


if(signal[i][j] == 1){//如果当前点属于连通子图,那么其左、上两个元素若为1,也属于连通子图


if(i > 0 && metric[i - 1][j] == 1) {


signal[i - 1][j] = 1;


metric[i - 1][j] = 2;


ones--;


}


if(j > 0 && metric[i][j - 1] == 1) {


signal[i][j - 1] = 1;


metric[i][j - 1] = 2;


ones--;


}


}


}


}


}


return signal;


}





/**


* 计算n行m列的01矩阵的连通子图要变成合法连通子图需要改变的元素数


* 步骤:判断每个元素的行和列上有没有出现过1,


* 如果出现过且与当前的1之间有0,则将之间的0全部变为1,并count++


* @param n


* @param m


* @return count 该01矩阵要变成合法连通矩阵需要改变的元素数


*/


private static int countChanges(int n,int m,int[][]signal){


int count = 0;//记录需要改变的0的个数


int rowSignal = -1;//记录某一行是否有1出现


int[] colSignal = new int[m];//记录某一列是否有1出现


for(int i = 0;i < m;i++)colSignal[i] = -1;//初始化数组


for(int i = 0;i < n;i++){


for(int j = 0;j < m;j++){


if(signal[i][j] == 1){//如果当前数字为1则查看其与同行、同列的其他1之间有没有0,有的话将0变为1,并将count数加1


if((j > (rowSignal + 1)) && (rowSignal != -1)){//对行进行处理


while(++rowSignal < j){//将第i行中两个不相邻1的之间的0全部变为1


signal[i][rowSignal] = 1;


metric[i][rowSignal] = 2;


count++;


}





rowSignal = j;


if((i > (colSignal[j] + 1)) && (colSignal[j] != -1)){


while(++(colSignal[j]) < i){//将第j列中两个不相邻的1之间的0全部变为1


signal[colSignal[j]][j] = 1;


metric[colSignal[j]][j] = 2;


count++;


}


}


colSignal[j] = i;


}


}


}


return count;


}





/**


* 判断字符串str是否为数字


* @param str


* @return true/false


*/


public static boolean isNum(String str){ 


return str.matches("^[-+]?(([0-9]+)([.]([0-9]+))?|([.]([0-9]+))?)$"); 








/**


* 根据行列值从控制台读入01矩阵并得到这个连通矩阵变为合法的需要改变的0的个数


* @param n


* @param m


*/


@SuppressWarnings("resource")
public static int getMetric(int n,int m){


java.util.Scanner sin=new java.util.Scanner(System.in);


int count = 0;//该矩阵需要改变的0的个数


for(int i = 0;i < n;i++){


// String inputStr = scala.Console.readLine();


String inputStr = sin.nextLine();


String[] ss = inputStr.split(" ");


for(int j = 0;j < m;j++){//如果输入不是01矩阵,清空矩阵重新输入


if((!isNum(ss[j])) || (ss.length < m) || ((Integer.parseInt(ss[j]) != 0) && (Integer.parseInt(ss[j]) != 1))){


// System.out.println("请正确输入" + n + "行" + m + "列01矩阵(矩阵只能包含0和1字符,元素间以空格隔开)...");


i = -1;//清空矩阵


break;


}


metric[i][j] = Integer.parseInt(ss[j]);


if(metric[i][j] == 1) ones++;


}


}


while(ones > 0){


count += countChanges(n,m,getConnectedOnes(n,m));


}


return count;


}





@SuppressWarnings("resource")
public static void main(String[]args){


java.util.Scanner sin=new java.util.Scanner(System.in);


//System.out.println("“渣打科营‘Mini Code Marathon’赛题:连通块最少”开始...");


//System.out.println("请输入测试数据:");


int n = 0;


int m = 0;


int[]counts = new int[50];


int index = 0;//第index组测试数据


// String inputStr = scala.Console.readLine();


String inputStr = sin.nextLine();


while(!(inputStr.equals(""))){


String[] ss = inputStr.split(" ");


if(ss.length == 2 && isNum(ss[0]) && isNum(ss[1])) {


n = Integer.parseInt(ss[0]);


m = Integer.parseInt(ss[1]);


if(n > 0 && n <= 50 && m > 0 && m <= 50){


counts[index++] = getMetric(Integer.parseInt(ss[0]),Integer.parseInt(ss[1]));


}else System.out.println("请正确输入01矩阵的行(n)、列(m),(正整数n,m(0<n,m<=50)))...");


}else System.out.println("请正确输入01矩阵的行(n)、列(m),(正整数n,m(0<n,m<=50)))...");


// System.out.println("合法的连通矩阵:");
//
// for(int i = 0;i < n;i++){//输出合法的连通矩阵
//
// for(int j = 0;j < m;j++)
//
// System.out.print(metric[i][j] + " ");
//
// System.out.println();


// }


// System.out.println("请输入下一组测试数据,若要结束,直接回车...");


// inputStr = scala.Console.readLine();


inputStr = sin.nextLine();


}


for(int i = 0;i < index;i++)System.out.println(counts[i]);


}


}



Plus:今天没啥事,就试着写了写,想着各种情况考虑的挺周全的,eclipse/myeclipse运行也都通过了,测试结果没问题,但是提交代码之后,被告知挑战失败,说是可能除数为0导致、、、话说这里好像根本没有乘除运算来者、、、、

罢了,天生没有天外来财的命,失败就失败吧,就是很纠结不知道错在哪里。。。。

0 0
原创粉丝点击