算法技巧-翻硬币问题java

1902 翻硬币
有N枚硬币,编号1到N。现在有如下4种操作:

1、翻转所有硬币,即正的变成反的,反的变成正的。
2、翻转所有奇数号的硬币。
3、翻转所有偶数号的硬币。
4、翻转所有编号形式为 3M+1(M>=0)3M+1(M>=0) 的硬币。

刚开始的时候所有硬币都是正面朝上,现在给出经过P次操作之后某些硬币的正反状态,请计算一下P次操作之后,有哪些状态符合这些条件。

输入单组测试数据。
第一行有两个整数N(10 <= N <= 100)和P(1 <= P <= 10000 )。
第二行给出若干个整数(不超过N个),表示最后正面朝上的硬币编号,输入-1结束。
第三行给出若干个整数(不超过N个),表示最后反面朝上的硬币编号,输入-1结束。
输出所有符合条件的最终状态。每行一个,输出N个字符,第i个字符表示第i个硬币的状态,1表示正面朝上,0代表反面朝上。按照字典序从小到大输出,如果没有符合要求的最终状态,输出IMPOSSIBLE。
样例输入1
10 2
-1
7 -1
样例输出1
0000000000
0011100011
0101010101

第一眼看到可能是深搜问题,递归改变状态,可以实现,但针对比较大的数据就会超时,后来仔细研究了一下题得出
每种操作同时操作两次会变回原状态,也就是说每种只有操作了一次和没有操作,通过对四种方法做和不做的组合,一共有2的4次方16种状态,只要根据p的数据对于2取余判断奇偶性,再和16种状态中的奇偶性对比就行了

java代码:

import java.util.ArrayList;
import java.util.Collections;
import java.util.Scanner;
public class jjj {
 static ArrayList<Integer> z = new ArrayList<Integer>();//存储最后正面的状态
 static ArrayList<Integer> f = new ArrayList<Integer>();//存储最后反面的状态
 static ArrayList<String> max = new ArrayList<String>();//存储最后的情况
 public static void main(String[] args) {
  Scanner sc = new Scanner(System.in);
  int n = sc.nextInt();
  int[] l = new int[n];//表示当前的状态
  for (int i = 0; i < l.length; i++) {
   l[i]=1;//初识状态为一
  }
  int p = sc.nextInt();
  int zz = sc.nextInt()-1;//正面的状态
  while (zz>=0) {
   z.add(zz);
   zz=sc.nextInt()-1;
  }
  int ff = sc.nextInt()-1;//反面的状态
  while (ff>=0) {
   f.add(ff);
   ff=sc.nextInt()-1;
  }
  String s = "";
  if (p%2==0) {//偶数情况
    if (p(l)) {//不操作
      for (int i : l) {
        s+=i;
      }
      if (!max.contains(s)) {
        max.add(s);
      }
      s="";
    }
    if (p>=2) {//操作两次
    for (int i = 1; i <= 4; i++) {
     for (int j = i+1; j <= 4; j++) {
      fz(l,i);
      fz(l,j);
      if (p(l)) {
       for (int in : l) {
        s+=in;
       }
       if (!max.contains(s)) {
        max.add(s);
       }
       s="";
      }
      fz(l,j);
      fz(l,i);
     }
    }
   }
    if (p%4==0&&p>=4) {//操作四次
    fz(l,4);
    if (p(l)) {
     for (int in : l) {
      s+=in;
     }
     if (!max.contains(s)) {
      max.add(s);
     }
     s="";
    }
    fz(l,4);
   }
  }
   if (p%2==1) {//奇数情况
    	for (int i = 1; i <= 4; i++) {//一次情况
    		fz(l,i);
    		if (p(l)) {
     			for (int in : l) {
      				s+=in;
     			}
     			if (!max.contains(s)) {
      				max.add(s);
     			}
     			s="";
    		}
    		fz(l,i);
   	}
   if (p>=3) {
    for (int i = 1; i <= 4; i++) {//三次情况
     for (int j = i+1; j <= 4; j++) {
      for (int k = j+1; k <= 4; k++) {
       fz(l,i);
       fz(l,j);
       fz(l,k);
       if (p(l)) {
        for (int in : l) {
         s+=in;
        }
        if (!max.contains(s)) {
         max.add(s);
        }
        s="";
       }
       fz(l,k);
       fz(l,j);
       fz(l,i);
      }
     }
    }
   }
   
   }
   if (max.size()==0) {//无满足状态
   	System.out.println("IMPOSSIBLE");
   	return;
   }
   Collections.sort(max);//排序字典序输出
   for (int i = 0; i < max.size(); i++) {
   	System.out.println(max.get(i));
   }
 }
 private static void fz(int[] l, int i) {//1234种操作
  if (i==1) {
   for (int j = 0; j < l.length; j++) {
    l[j]=1-l[j];
   }
  }else if(i==2){
   for (int j = 0; j < l.length; j+=2) {
    l[j]=1-l[j];
   }
  }else if (i==3) {
   for (int j = 1; j < l.length; j+=2) {
    l[j]=1-l[j];
   }
  }else if (i==4) {
   for (int j = 0; j < l.length; j+=3) {
    l[j]=1-l[j];
   }
  }
 }
 private static boolean p(int[] l) {//判断是否满足条件
  if (z.size()!=0) {
   for (int i = 0; i < z.size(); i++) {
    if (l[z.get(i)]!=1) {
     return false;
    }
   }
  }
  if (f.size()!=0) {
   for (int i = 0; i < f.size(); i++) {
    if (l[f.get(i)]!=0) {
     return false;
    }
   }
  }
  return true;
 }
}

代码量较多,希望有大佬可以给指点指点

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

PROBIE_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值