2069 - 翻木板
时间限制 : 3 秒
内存限制 : 128 MB
最近ayit举办了一场翻木板游戏比赛,游戏规则是这样的:有一个大机器,里面放一排共m(0<m<21)个木板,分别编号为0到m-1,机器外面有k(0<k<200)个按钮,每个按钮可以翻转一些木板,游戏开始时木板都是正面朝上,现在必须通过按钮把木板全部翻成反面朝上,谁用的次数最少就是获胜者。yaling童鞋参加了这个比赛,大家帮他算算完成这个游戏至少需要按多少次按钮。
题目输入
有多组测试数据。每组测试数据第一行为 m 和 k 。接下来有k行数字,代表k个按钮,每行数字的第一个数 n 代表相应的按钮可以翻转 n 个木板,随后又有 n 个数字,表示按钮可以翻转木板的编号。
题目输出
输出一个数字占一行,表示至少需要按按钮的次数。数据保证有解。
输入/输出样例
输入格式
3 2 1 0 2 1 2 3 3 2 0 1 1 1 2 1 2
输出格式
2 3
C++解答
#include <cstdio> #include <cstring> #include <queue> using namespace std ; int visit[5000000] ; int main() { // freopen("in.txt" , "r" , stdin ) ; int n ; int on[100010] ; while( ~scanf("%d" , &n ) ) { int k ; scanf("%d" , &k ) ; memset( on , 0 , sizeof( on ) ) ; memset( visit , -1 , sizeof( visit ) ) ; for( int i = 0 ; i < k ; i ++ ) { int t ; scanf("%d" , &t ) ; for( int j = 0 ; j < t ; j ++ ) { int m ; scanf("%d" , &m ) ; on[i] = on[i] | ( 1 << m ) ; } } queue<int> q ; q.push(0) ; visit[0] = 0 ; while( !q.empty() ) { int t = q.front() ; q.pop() ; for( int i = 0 ; i < k ;i ++ ) { int tt = t ^ on[i] ; if( visit[tt] == -1 ) { visit[tt] = visit[t] + 1 ; q.push( tt ) ; if(visit[(1<<n)-1] != -1) break ; } } if(visit[(1<<n)-1] != -1) break ; } if( visit[(1<<n)-1] != -1 ) { printf("%d\n" , visit[(1<<n)-1]) ; } else { printf("no solver!\n") ; } } return 0 ; }
Java解答
import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Scanner; public class Main { int m,k; int[] B; public Main() { Scanner sc=new Scanner(System.in); //sc.hasNextInt(); while(sc.hasNextInt()) { m=sc.nextInt(); k=sc.nextInt(); int start=(1<<m)-1; B=new int[k]; for(int i=0;i<k;i++) { int zero=0; //000 //001 按钮 翻转0号位 最右边一位 int n=sc.nextInt(); for(int a=0;a<n;a++) { int temp=sc.nextInt(); zero=zero|(1<<temp); //把第temp位上设置为1 } B[i]=zero; //System.out.println(zero); } ArrayList<Node> AL=new ArrayList<Node>(); //队列 Node startnode=new Node(start,0); startnode.Mark='S';//加上开始标记s Node goalnode=new Node(0,0); goalnode.Mark='G'; //加上终止拓展标记G HashMap<Integer,Node> StartSet=new HashMap<Integer,Node>(); StartSet.put(start,startnode);//开始格局 映射到startnode HashMap<Integer,Node> GoalSet=new HashMap<Integer,Node>(); GoalSet.put(0,goalnode);//目标格局 映射到goalnode AL.add(startnode); AL.add(goalnode); //开始状态和目标状态加入队列 int index=0; boolean success=true; while(index<AL.size() && success) { Node current=AL.get(index); if(current.Mark=='S'&&GoalSet.containsKey(current.align)) //判断是否目标状态 { System.out.println(current.step+GoalSet.get(current.align).step); success=false; break; } if(current.Mark=='G'&&StartSet.containsKey(current.align)) //判断是否目标状态 { System.out.println(current.step+StartSet.get(current.align).step); success=false; break; } for(int i=0;i<k;i++) { int newalign=current.align^B[i]; //按下按钮,翻转 if(current.Mark=='S'&&StartSet.containsKey(newalign)==false||current.Mark=='G'&&GoalSet.containsKey(newalign)==false) { Node newstate=new Node(newalign,current.step+1); newstate.Mark=current.Mark; AL.add(newstate); if(newstate.Mark=='S') StartSet.put(newalign,newstate); else GoalSet.put(newalign, newstate); } } index++; } } } public static void main(String[] args) { // TODO Auto-generated method stub Main tk=new Main(); } class Node{ public Node(int a,int s) { align=a;step=s; } int align; //排列 int step; //步数 char Mark;//标记开始拓展 还是 结束拓展 } }