算法
利用全排列来代替爆搜,因为每个走法只能对应一个全排列,简化了搜索。只需要判断每次全排列是否能从第一个点走到第二个点,以及在连续的三个点中方向是否改变,以及能否从最后一个点回到原点。get函数来判断两个点的方向。
利用pair数对
来存储奶牛的坐标。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 get函数 int get (PII a, PII b) { if (a.first != b.first && a.second != b.second) return -1 ; if (a.first == b.first) { if (b.second > a.second) return 0 ; else return 2 ; } if (b.first > a.first) return 1 ; return 3 ; } int res = 0 ; do { int last = get (p[0 ], p[q[1 ]]); if (last == -1 ) continue ; for (int i = 1 ; i <= n; i ++) { int d = get (p[q[i]], p[q[i + 1 ]]); if (d == -1 || d == last) { last = -1 ; break ; } last = d; } if (last != -1 ) res ++; }while (next_permutation (q + 1 , q + 1 + n));
普通枚举:
枚举四种情况,三条横线,三条竖线,两横一竖,两竖一横。三条横线只要枚举所有点的横坐标是否超过了三种;三条竖线同理;两横一竖枚举一竖的那种情况,将在同一竖的点去掉之后,在枚举剩下的点是否能用两条横线包括;两竖一横同理。
$dfs$ 枚举:
最多枚举八种情况,所以时间复杂度只有$O(8N)$ ,从任意一个点开始枚举,每个点只有两种情况,分别枚举横线和竖线的情况,只要枚举超过三条还没有将所有的点包括就是不成功;另外用哈希表 来存储横线和竖线。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 int dfs (int u, int cnt) { if (cnt > 3 ) return 0 ; if (u == n) return 1 ; if (row.count (p[u].y) || col.count (p[u].x)) return dfs (u + 1 , cnt); row.insert (p[u].y); if (dfs (u + 1 , cnt + 1 )) return 1 ; row.erase (p[u].y); col.insert (p[u].x); if (dfs (u + 1 , cnt + 1 )) return 1 ; col.erase (p[u].x); return 0 ; }
java 线程
1.线程通常都有五种状态,创建 、就绪 、运行 、阻塞 和死亡 。
2.调用start()方法后,线程的状态是“就绪”状态,而不是“运行”状态;线程要等待CPU调度,不同的JVM 有不同的调度算法,线程何时被调度是未知的。因此,start()方法的被调用顺序不能决定线程的执行顺序。
3.run()方法的执行是不是需要线程调用start()方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 public class Race implements Runnable { private static String winner; @Override public void run () { for (int i = 0 ; i <= 100 ; i ++) { if (Thread.currentThread().getName().equals("兔子" ) && i % 10 == 0 ) { try { Thread.sleep(10 ); } catch (InterruptedException e) { e.printStackTrace(); } } boolean flag = gameOver(i); if (flag) { break ; } System.out.println(Thread.currentThread().getName() + "-->跑了" + i); } } private boolean gameOver (int steps) { if (winner != null ) { return true ; } if (steps >= 100 ) { winner = Thread.currentThread().getName(); System.out.println("winner is" + winner); return true ; } return false ; } public static void main (String[] args) { Race race = new Race (); new Thread (race, "兔子" ).start(); new Thread (race, "乌龟" ).start(); } }
多线程实现callable接口 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 实现callable接口 public class TestCallable implements Callable <Boolean> { public Boolean call () throws Exception { WebDownLoad webdownload = new WebDownLoad (); webdownload.download(url, name); System.out.println("下载了文件名为:" + name); return true ; } } 多线程的使用方式 public static void main (String[] args) throws ExecutionException, InterruptedException { TestCallable t1 = new TestCallable ("https://img.alicdn.com/imgextra/i4/1015368528/O1CN01pAlQgg2CrsOImdwzJ_!!1015368528.jpg" ,"1.jpg" ); TestCallable t2 = new TestCallable ("https://img.alicdn.com/imgextra/i4/1015368528/O1CN01pAlQgg2CrsOImdwzJ_!!1015368528.jpg" ,"2.jpg" ); TestCallable t3 = new TestCallable ("https://img.alicdn.com/imgextra/i4/1015368528/O1CN01pAlQgg2CrsOImdwzJ_!!1015368528.jpg" ,"3.jpg" ); ExecutorService ser = Executors.newFixedThreadPool(3 ); Future<Boolean> r1 = ser.submit(t1); Future<Boolean> r2 = ser.submit(t2); Future<Boolean> r3 = ser.submit(t3); Boolean rs1 = r1.get(); Boolean rs2 = r2.get(); Boolean rs3 = r3.get(); ser.shutdownNow(); }
Lambda
Lambda 表达式只能有一行代码的情况下才能简化成为一行(将花括号去掉 ),如果有多行,那么就用代码快包裹 ;前提是接口为函数式接口;多个参数也可以去掉参数类型,要去掉就都去掉,必须加上括号。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 public class TestLambda { public static void main (String[] args) { ILike like = new Like (); like.like(); like = () ->{ System.out.println("i like you2" ); }; like.like(); } } interface ILike { void like () ; } class Like implements ILike { @Override public void like () { System.out.println("I like you forever" ); } } 输出结果为: I like you forever i like you2
线程停止
建议使用一个标志位进行终止变量,当flag=false,则终止线程运行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 public class TestStop implements Runnable { private Boolean flag = true ; @Override public void run () { int i = 0 ; while (flag) { System.out.println("run ----- Thread" + i ++); } } public void stop () { this .flag = false ; } public static void main (String[] args) { TestStop testStop = new TestStop (); new Thread (testStop).start(); for (int i = 0 ; i < 100 ; i++) { System.out.println("main---run---" + i); if (i == 90 ) { testStop.stop(); System.out.println("线程已停止----" ); } } } }
礼让线程
让当前正在执行的线程暂定,但不阻塞,用yield()方法,Thread.yield()
;
join线程插队
join
合并线程,待此线程执行完成后,在执行其他线程,其他线程阻塞,可以看成是插队。
线程优先级
线程的优先级用数字表示,范围从1~10; 默认是5,数字越大优先级越高;可以用setPriority()
和getPriority()
分别修改和获取线程优先级。
优先级的设定建议在start()
调度前。
Thread.MIN_PRIORITY= 1
;
Thread.MAX_PRIORITY= 1
;
Thread.NORM_PRIORITY= 1
;
守护线程
线程分为用户线程和守护线程
虚拟机必须确保用户线程执行完毕
虚拟机不用等待守护线程执行完毕
如后台记录操作日志,监控内存,垃圾回收等待
1 2 Thread thread = new Thread (god);thread.setDaemon(true );