您的位置:首页 > 编程语言 > Java开发

纵横火柴 java 蓝桥杯 复习中.....

2018-03-14 14:36 134 查看
 这是一个纵横火柴棒游戏。如图[1.jpg],在3x4的格子中,游戏的双方轮流放置火柴棒。其规则是: 
 


    
1. 不能放置在已经放置火柴棒的地方(即只能在空格中放置)。 
    2. 火柴棒的方向只能是竖直或水平放置。 
 
    3. 火柴棒不能与其它格子中的火柴“连通”。所谓连通是指两根火柴棒可以连成一条直线,且中间没有其它不同方向的火柴“阻拦”。 
 
    例如:图[1.jpg]所示的局面下,可以在C2位置竖直放置(为了方便描述格子位置,图中左、下都添加了标记),但不能水平放置,因为会与A2连通。同样道理,B2,B3,D2此时两种方向都不可以放置。但如果C2竖直放置后,D2就可以水平放置了,因为不再会与A2连通(受到了C2的阻挡)。 
 
    4. 游戏双方轮流放置火柴,不可以弃权,也不可以放多根。直到某一方无法继续放置,则该方为负(输的一方)。 
 
    游戏开始时可能已经放置了多根火柴。 
 
    你的任务是:编写程序,读入初始状态,计算出对自己最有利的放置方法并输出。 
 
    如图[1.jpg]的局面表示为: 
 
00-1 
-000 
0100 
 
    即用“0”表示空闲位置,用“1”表示竖直放置,用“-”表示水平放置。 
 
【输入、输出格式要求】 
   
    用户先输入整数 n(n<100), 表示接下来将输入 n 种初始局面,每种局面占3行(多个局面间没有空白行)。 
 
    程序则输出:每种初始局面情况下计算得出的最佳放置法(行号+列号+放置方式)。 
 
    例如:用户输入: 
20111-000-000<
4000
/span>1111----0010
 
   则程序可以输出: 
00- 
211 
 
   不难猜出,输出结果的含义为: 
    
   对第一个局面,在第0行第0列水平放置 
    
   对第二个局面,在第2行第1列垂直放置 
 
   注意: 
    
   行号、列号都是从0开始计数的。 
        
   对每种局面可能有多个最佳放置方法(解不唯一),只输出一种即可。 
 
   例如,对第一个局面,001 也是正解;最第二个局面,201也是正解。 
 
 
 
【注意】 
 
    请仔细调试!您的程序只有能运行出正确结果的时候才有机会得分! 
    

其实,这道题目的核心是到底怎样的一种格局才算是对本方有利的,我们可以这样想:我们的最终目标是让对方无处可放,也就是合法的摆放方案为0,那我们在每一步的目标自然就是让对方可以摆放的方案越少越好。于是,可以得出结论,存在这么一种摆法,当我方按照这种方式摆放后,对方可以摆放的方案数最少。
分析完了之后自然就要想如何实现,首先,我们需要知道某一种摆放方案是否合法,即在r行c列摆放“-”或“1”到底是不是合法的,我设计了一种判断方法,有点麻烦:
1.判断所要摆放的是“-”还是“1”2.如果是“-”,就扫描这一行,看看有没有不满足题意的情况,如果是“1”,就扫描这一列,判断有没有不满足条件的情况,因为情况比较少,所以我就把每种情况都拿出来了。
之后我们就开始搜索所有可能的情况,即假如我们放在第一个合法的位置,对手有几种放法,第二个,第三个......然后每次遇到更小的情况后就记录一下我们在哪个位置放了哪种火柴棍,最后输出最小的那种情况。    import java.util.Scanner;

public class Main15 {
//纵横放火柴
//这个解法只解决了在空地放子这个问题 但是没有完成题中要求 最有利的放置方案
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
char[][] state = new char[3][4];
String s;
sc.nextLine();
while((n--)>=0){

for(int i=0;i<3;i++){
s=sc.nextLine();
for(int j=0;j<4;j++){
state[i][j]=s.charAt(j);
}
}
jasdklf(state);
}
}
public static void jasdklf(char[][] state){
// int count;
for(int i=0;i<3;i++){
//count=0;
for(int j=0;j<4;j++){
if(state[i][j]=='0'){
//未放置的状态 就是下棋落子
state[i][j]='-';
if(isOk(state,i,j)){
//如果这个算法真的要去做到最有利 即在这个可以放置之后 除去这个位置 剩下来0的位置 就是对手可以放的棋子的位置

// for(int h=0;h<3;h++){
// for(int k=0;k<4;k++){
// if(state[h][k]=='0'){
// state[h][k]='-';
// if(isOk(state,h,k)){
// count++;
// }else{
// state[h][k]='0';
// state[h][k]='1';
// if(isOk(state,h,k)){
// ....
// count++;
// }
// }
// }
// }
// }
//类似于这种 如果count的数目最小 即是我们要求的答案
System.out.println(i+""+j+"-");
return;
}
//如果放不了水平的子 还原
state[i][j]='0';
state[i][j]='1';
if(isOk(state,i,j)){
System.out.println(i+""+j+"-");
return;
}
state[i][j]='0';
}
}
}
}
//这个方法其实就是看所在的这个二维数组 如果是水平放置看同一行 竖直放置看 同一列
public static boolean isOk(char[][] state,int i,int j){
if(state[i][j]=='-'){
for(int j2=j+1;j2<4;j2++){
if(state[i][j2]=='-'){
return false;
}else if(state[i][j2]=='1'){
return true;
}
}
for(int j2=j-1;j2>=0;j2--){
if(state[i][j2]=='-'){
return false;
}else if(state[i][j2]=='1'){
return true;
}
}
}else if (state[i][j]=='1'){
for(int i2=i+1;i2<3;i2++){
if(state[i2][j]=='1'){
return false;
}else if(state[i2][j]=='-'){
return true;
}
}
for(int i2=i-1;i2>=0;i2--){
if(state[i2][j]=='1'){
return false;
} else if(state[i2][j]=='-'){
return true;
}
}
}
return true;
}
}
贴上复习资料中的算法
   import java.util.Scanner;
import java.util.List;
import java.util.ArrayList;
public class Demo05 {
static boolean flag = false; // 用来标记是否连通
static boolean flag2 = false; // 用来标记是否没有结果, 如果没有结果输出"空";
// 初始化数组
public static void init(List<char[][]> lis,String[] s,int n){
for(int i=0;i<n;i++){
for(int j=i*3;j<i*3+3;j++){
lis.get(i)[j%3] = s[j].toCharArray();
}
}
}
// 创建n个数组 初始化,并存入lis
public static void input(List<char[][]> lis,int n){
Scanner scan = new Scanner(System.in);
for(int i=1;i<=n;i++){ // 创建数组
lis.add(new char[3][4]);
}
String[] s = new String[n*3];
for(int i=0;i<n*3;i++){ // 行到输入的数据
s[i] = scan.nextLine();
}
init(lis,s,n); // 用输入的数据 初始化每个数组
}
// c='1' 检查列上侧是否连通
public static boolean colU(char[][] m,int i,int j,char c){
if(i<0){
flag = true; // 都不连通
return flag;
}
if(m[i][j]=='0'){
return colU(m,i-1,j,c);
}else if(m[i][j]=='1'){
flag = false; // 有一个 '1' 则连通
return flag;
}else if(m[i][j]=='-'){
flag = true; // 有一个 '-' 则不连通
return flag;
}
return flag;
}
// c='1' 检查列下侧是否连通
public static boolean colD(char[][] m,int i,int j,char c){
if(i>=m.length){
flag = true; // 都不连通
return flag;
}
if(m[i][j]=='0'){
return colD(m,i+1,j,c);
}else if(m[i][j]=='1'){
flag = false; // 有一个 '1' 则连通
return flag;
}else if(m[i][j]=='-'){
flag = true; // 有一个 '-' 则不连通
return flag;
}
return flag;
}
// c='-' 检查行左侧是否连通
public static boolean rowL(char[][] m,int i,int j,char c){
if(j<0){
flag = true; // 都不连通
return flag;
}
if(m[i][j]=='0'){
return rowL(m,i,j-1,c);
}else if(m[i][j]=='1'){
flag = true; // 有一个 '1' 则不连通
return flag;
}else if(m[i][j]=='-'){
flag = false; // 有一个 '-' 则连通
return flag;
}
return flag;
}
// c='-' 检查行右侧是否连通
public static boolean rowR(char[][] m,int i,int j,char c){
if(j>=m[i].length){
flag = true; // 都不连通
return flag;
}
if(m[i][j]=='0'){
return rowR(m,i,j+1,c);
}else if(m[i][j]=='1'){
flag = true; // 有一个 '1' 则不连通
return flag;
}else if(m[i][j]=='-'){
flag = false; // 有一个 '-' 则连通
return flag;
}
return flag;
}
// 当c='1'时 检查是否连通1111111111111111111
public static boolean check1(char[][] m, int i, int j, char c) {
if(colU(m,i,j,c)&&colD(m,i,j,c)){ // 是 '1' 时 检查(上下)是否连通
flag = true;
}else{
return false;
}
return flag;
}
// 当c='-'时 检查是否连通-------------------
public static boolean check2(char[][] m, int i, int j, char c) {
if(rowL(m,i,j,c)&&rowR(m,i,j,c)){ // 是 '-' 时 检查(左右)是否连通
flag = true;
}else{
return false;
}
return flag;
}
// 检测并添加元素
public static void calc2(char[][] m,int i,int j){
if(check1(m, i, j, '1')){ // 等于'1'时,行列都不连通
m[i][j] = '1'; // 则添加元素
}else if(check2(m, i, j, '-')){// 等于'-'时,行列都不连通
m[i][j] = '-';// 则添加元素
}else{
flag2 = true; // 表示无结果
}
}
// 计算函数的入口
public static void calc(char[][] m){
for(int i=0;i<m.length;i++){
for(int j=0;j<m[i].length;j++){
if(m[i][j]=='0'){
calc2(m,i,j); // 进入检测函数
}
if(flag){
String temp = i+""+j+""+m[i][j];
System.out.println(temp);
flag2 = false; // 如果有元素添加,那么就不为空!下边的就不必输出"空"值
break; // 如果添加过元素,则退出循环
}
}
if(flag){ // 如果添加过元素,则退出循环
flag = false;
break;
}
}
if(flag2){ // 如果无结果,则添加空
System.out.println("空");
flag2 = false; // 修改标记位
}
}
// 主函数
public static void main(String[] args){
Scanner scan = new Scanner(System.in);
List<char[][]> lis = new ArrayList<char[][]>(); // 存放每个数组
System.out.print("输入整数 n(n<100):");
// 创建n个数组 初始化,并存入lis
input(lis,scan.nextInt());
// 计算函数的入口, 单独去每个数组去测试
for(int i=0;i<lis.size();i++){
calc(lis.get(i));
}
}
}
这个就用到了最有放置........

这题的思路参考的是点击打开链接
原博主用的是c  但是思路很清晰  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: