长跑排名预测

 

参考代码

 1 public class yucepaiming {
 2     //存储运动员数量与围观党数量
 3     private static int n,m;
 4     //存储围观党预测结果
 5     private static String[][] s;
 6     //存储运动员排名顺序
 7     private static int[] list;
 8     //存储满足预测的结果总和
 9     private static int sum;
10     private static List<int[]> alist = new ArrayList<>();
11     public static void main(String[] args) {
12         String str = new Scanner(System.in).nextLine();
13         n = Integer.parseInt(str.split(" ")[0]);
14         m = Integer.parseInt(str.split(" ")[1]);
15         s = new String [m][];
16         for(int i=0;i<m;i++){
17             str = new Scanner(System.in).nextLine();
18             s[i]=str.split(" ");
19         }
20         //初始化排名,1号第一名,2号第二名...
21         list = new int[n];
22         for(int i=0;i<n;i++){
23             list[i]=i;
24         }
25         //使用回溯算法,参数为运动员排名,0为第一名
26         dg(0);
27         System.out.println(sum);
28         for(int[] a : alist){
29             str = Arrays.toString(a);
30             str = str.replace("[", "");
31             str = str.replace("]", "");
32             System.out.println(str);
33         }
34     }
35     private static void dg(int index) {
36         //当最后一个顺序已经排好并且满足预测条件的话
37         if(index == n && filter(list)){
38             sum++;
39             //注意必须重新复制数组,因为存入集合中的只是数组地址。如果没有复制,当数组改变时,集合的元素也会改变
40             alist.add(Arrays.copyOf(list, list.length));
41         }else{
42             /*交换顺序->排下一个运动员->还原顺序,注意当前交换顺序的运动员只能交换他后面的运动员的顺序,
43             这样交换的两个运动员在递归过程中才不会重复交换,产生错误的数据,所以i=index,而不是0 */
44             for(int i=index;i<n;i++){
45                 //交换顺序
46                 int t = list[i];
47                 list[i] = list[index];
48                 list[index] = t;
49                 //排下一个运动员
50                 dg(index+1);
51                 //还原顺序
52                 t = list[i];
53                 list[i] = list[index];
54                 list[index] = t;
55             }
56         }
57     }
58     private static boolean filter(int[] data) {
59         boolean falg = true;
60         for(int i=0;i<m;i++){
61             //这个预测是错误的
62             if(s[i][s[i].length-1].equals("0")){
63                 //当所以运动员都满足预测则预测错误
64                 for(int j=0,k=1;j<n;j++){
65                     if(Integer.parseInt(s[i][k])==list[j]&&++k==s[i].length-1){
66                         falg = false;
67                     }
68                 }
69             }else{//这个预测是正确的                
70                 falg = false;
71                 //当所以运动员都满足预测则预测正确
72                 for(int j=0,k=1;j<n;j++){
73                     //原理同错误预测
74                     if(Integer.parseInt(s[i][k])==list[j]&&++k==s[i].length-1){
75                         falg = true;
76                     }
77                 }
78             }
79         }
80         return falg;
81     }
82 }

运行结果

 注意:

1                 for(int j=0,k=1;j<n;j++){
2                     if(Integer.parseInt(s[i][k])==list[j]&&++k==s[i].length-1){
3                         falg = false;
4                     }
5                 }

这段代码意思是当所以运动员都满足预测则预测错误

别看这个if语句只有一行,逻辑还是特别复杂的
首先要明白&&,当左边不满足,右边就不会执行了
当第一次执行Integer.parseInt(s[i][k])==list[j]满足条件时,会把第i个围观党预测的第一个人从已经排好的数组list中找出来
这时k为围观党预测的人在s[i][]中的下标,j为list数组中的下标,他们指的同一个运动员
当第一个条件满足会执行++k==s[i].length-1,这句话的意思是如果++k超过了存预测部分的长度,换句话说就是当前k下标是最后一个预测
因为s数组最后还存了一个状态,这句话的对错与否,所以s[i].length-1
所以这个循环加上if判断的运行过程就是:
在排名中找到第一个预测,判断这个预测是不是最后一个预测(当预测只有一个人会判断为预测错误,当然这样的预测是无意义的),
如果是则判断为预测错误,否则判断下一个预测(k++),然后找到运动员排名位置(Integer.parseInt(s[i][k])==list[j]),
注意循环是j++,也就是找到的运动员必须在上一个运动员后面的,这样才能满足预测
如果找不到k则在循环结束都不可能满足++k==s[i].length-1,则说明预测正确,否则判断当前是否为最后一个,若是,则说明所有预测都成立,
则返回预测错误,若不是最后一个,则判断下一个预测

原文地址:https://www.cnblogs.com/chengpu/p/algorithm5.html