以下代码答案为83,正确答案应为80,分析之后,发现问题在于判断连通的代码是不够正确的。
check()方法简单来说是判断给定的组合中只要没有落单的二极管就返回true。
对于找一根二极管,都返回true。
对于找二三五六七根二极管,简单分析可以得知,只要没有落单的,所有的二极管必然连成一片。
分析两根二极管,很显然,只有两个,所以只要没有落单的,这两根必然连在一起;分析三根二极管,想要不落单,只要两根在一起,而3=2+1,所有除非三根连在一起,否则必然有落单,即只要没有落单的,三根必然连成一片;分析五根二极管,不落单可以2+3也可以5,但是发现,对于此图来说,所有的2+3都是连成一片的,换句话说,在此图中找不到一个分开的2+3组合;分析找六根二极管,总共就七种情况,可以看到,去掉任意一根,剩下的六根都是连通的;七根二极管更不用说,一定连通。
而只有对于四根二极管,出现了没有落单的,但却整体不连通的情况。
经分析,可以知道是abde、acdf、bcef这三种情况。因此比正确答案多3。
public class Seven {
public static char[] c="abcdefg".toCharArray();
public static char[][] table= {
{'b','f'},
{'a','c','g'},
{'b','d','g'},
{'c','e'},
{'d','f','g'},
{'a','e','g'},
{'b','c','e','f'}
};
public static int ans=0;
public static void main(String[] args) {
for(int i=1;i<=7;i++) {
//要找i根,初始情况:一个也没找到,从c[0]开始找,现在的结果是“”
dfs(0,0,i,"");
}
System.out.println(ans);
}
public static void dfs(int cnt,int pos,int n,String s) {
//找到n根了,不用再看了
if(cnt==n) {
if(check(s)) {
System.out.println(s);
ans++;
}
return;
}
//七根都看完了,没了,回去吧
if(pos==c.length) return;
//一共七根二极管,我们要找出n根,c[pos]七根二极管中的一根,那么对于每一个二极管来说,有以下两种情况:
dfs(cnt+1,pos+1,n,s+c[pos]);//要当前的二极管,带上,走看下一个
dfs(cnt,pos+1,n,s);//不要当前的,直接去看下一个
}
public static boolean check(String s) {
char[] c=s.toCharArray();
agent:for(int i=0;i<c.length;i++) {
char[] t=s.replaceAll(c[i]+"", "").toCharArray();
for(int j=0;j<t.length;j++) {
int k;
for(k=0;k<table[c[i]-'a'].length&&t[j]!=table[c[i]-'a'][k];k++);
if(k!=table[c[i]-'a'].length)
continue agent;
}
if(c.length!=1)
return false;
}
return true;
}
}
修改了判断连通的方法,答案正确为80,代码如下:
public class Test{
public static char[] c="abcdefg".toCharArray();
public static char[][] table= {
{'b','f'},
{'a','c','g'},
{'b','d','g'},
{'c','e'},
{'d','f','g'},
{'a','e','g'},
{'b','c','e','f'}
};
public static int ans=0;
public static void main(String[] args) {
for(int i=1;i<=7;i++) {
//要找i根,初始情况:一个也没找到,从c[0]开始找,现在的结果是“”
dfs(0,0,i,"");
}
System.out.println(ans);
}
public static void dfs(int cnt,int pos,int n,String s) {
//找到n根了,不用再看了
if(cnt==n) {
if(check(s)) {
System.out.println(s);
ans++;
}
return;
}
//七根都看完了,没了,回去吧
if(pos==c.length) return;
//一共七根二极管,我们要找出n根,c[pos]七根二极管中的一根,那么对于每一个二极管来说,有以下两种情况:
dfs(cnt+1,pos+1,n,s+c[pos]);//要当前的二极管,带上,走看下一个
dfs(cnt,pos+1,n,s);//不要当前的,直接去看下一个
}
//检查是否连通
public static boolean check(String s) {
if(s.length()==1) return true;
char[] c=s.toCharArray();
//state数组存放c数组中对应字符的状态
int[] state=new int[c.length];
state[0]=1;
//cnt0表示state数组中元素值为0的元素个数,即还未被连接上的二极管个数
int cnt0=state.length-1;
//可以这样想象:我们要建立一棵树,数组c里面放的是提供给我们的结点
//并不是任意的结点都可以连接起来,他们之间有着一定的规则,这个规则即为二维数组table
//当一个结点的状态state[i]==1,代表它已经连接到了树上,且它还可以连接其他结点
//当一个结点的状态state[i]==0,代表它还未连接到树上
//当一个结点的状态state[i]==2,代表它已经连接到树上,且不能再连接其他结点
while(cnt0!=0) {//当cnt0==0,代表未连接结点个数为0,即所有的结点都连接到树上了,
//即字符串s代表的二极管组合是连成一片的
boolean flag=true;
//只要cnt0!=0,即还存在未连接结点,就要遍历数组c,找到状态为1的结点
//换句话说,这个for对数组c遍历时,只对状态为1的结点进行操作
//进而可以理解为这个for是在遍历状态为1的结点,当状态为0时,循环体相当于什么也没做就i++下一个了
for(int i=0;i<c.length;i++) {
if(state[i]==1) {
//当找到状态为1的结点,再次遍历数组c,这次要找的是状态为0的结点
for(int j=1;j<c.length;j++) {//c[0]的状态必定不为0,所以j从1开始遍历
if(state[j]==0) {
//找到状态为0的结点,与当前找到的状态为1的结点匹配
int k;
for(k=0;k<table[c[i]-'a'].length&&c[j]!=table[c[i]-'a'][k];k++);
if(k!=table[c[i]-'a'].length) {
//如果有邻接关系,即匹配成功
//则改变未连接结点的状态,变为1
state[j]=1;
flag=false;
cnt0--;//未连接结点的个数减1
}
}
}
//经过上面的for循环,有两种结果
//第一种是未连接结点中存在当前结点c[i]可以连接的结点,现在已经全部连接上
//第二种是未连接结点中不存在当前结点可以连接的,当前结点没有连接新的结点
//如果是第一种,经过上面的for,能连的已经连上,结果是当前结点不能再连其他结点了
//如果是第二种,经过上面的for,证明已经不能再连了
//无论是第一种还是第二种,当前结点的状态都要变成2
state[i]++;
}
}
//如果flag为true,说明数组c中状态为0的未连接结点个数没有变化
//也就说明这些未连接结点无法连接到树上,即s代表的二极管组合是没有全部连成一体的
if(flag) return false;
}
return true;
}
}
在网上看了看,学了另一种解法,即把给出的七段码的图转化为一个二维数组,这样就相当于直接存储了了每根二极管之间的邻接关系,只要像走迷宫一样,从每个点出发,找出所有的可能路径,再利用set集合的自动去重功能,最后set的size即为所求。
dfs要注意更新状态和回溯状态。
以下为代码:
import java.util.Arrays;
import java.util.HashSet;
//把七段码按位置存为二维数组,从不同起点出发,找所有路径,再利用set集合去掉重复,最后set的size即为所求
public class SevenIII {
static char[][] seven= {
{'a','b',' '},
{'f','g','c'},
{' ','e','d'}
};
static int[][] state=new int[3][3];
static int[][] move= {
{0,1},
{1,0},
{0,-1},
{-1,0}
};
static HashSet<String> set=new HashSet<>();
static String s="";
public static void main(String[] args) {
for(int i=0;i<seven.length;i++) {
for( int j=0;j<seven[i].length;j++) {
if(seven[i][j]!=' ') {
s+=seven[i][j];
set.add(s);
state[i][j]=1;
dfs(i,j);
state[i][j]=0;
s=s.replaceAll(seven[i][j]+"","");
}
}
}
for(String s:set) {
System.out.println(s);
}
System.out.println(set.size());
}
public static void dfs(int i,int j) {
for(int k=0;k<move.length;k++) {
int ii=i+move[k][0];
int jj=j+move[k][1];
if(ii>-1&&ii<seven.length&&jj>-1&&jj<seven[ii].length&&state[ii][jj]==0) {
s+=seven[ii][jj];
process();
set.add(s);
state[ii][jj]=1;
dfs(ii,jj);
state[ii][jj]=0;
s=s.replaceAll(seven[ii][jj]+"","");
}
}
}
public static void process() {
s=s.replaceAll(" ", "");
char[] c=s.toCharArray();
Arrays.sort(c);
s=String.valueOf(c);
}
}