抽签(放回抽取)
题目
代码
import java.util.Scanner;
//枚举四重循环
public class 抽签 {
private static int[] k;
private static int n;
private static int m;
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
n = sc.nextInt();
m = sc.nextInt();
k = new int[n];
for(int i=0;i<n;i++){
k[i]=sc.nextInt();
}
boolean flag=false;
//重复拿取
for(int a=0;a<n;a++){
for(int b=0;b<n;b++){
for(int c=0;c<n;c++){
for(int d=0;d<n;d++){
if(k[a]+k[b]+k[c]+k[d]==m){
flag=true;
break;
}
}
}
}
}
if(flag)
System.out.println("Yes");
else
System.out.println("No");
}
}
增加难度的抽签
二分搜索与O(n^3logn)
二分查找的负责度是O(logn)时间的,我们称这种阶的运行时间为对数时间。即便n变得很大,对数时间的算法依然非常快速
例如
最内侧的循环替换为二分搜索算法之后,就变成
输入输出
package 程序设计竞赛;
import java.util.Arrays;
import java.util.Scanner;
public class 难度增加的抽签 {
private static int n;
private static int m;
private static int[] k;
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc=new Scanner(System.in);
n = sc.nextInt();
m = sc.nextInt();
k = new int[n];
boolean flag=false;
for(int i=0;i<n;i++){
k[i]=sc.nextInt();
}
//为了执行二分法查找需要先排序
Arrays.sort(k);
for(int a=0;a<n;a++){
for(int b=0;b<n;b++){
for(int c=0;c<n;c++){
if(binary_search(m-k[a]-k[b]-k[c])){
flag=true;
}
}
}
}
if(flag)
System.out.println("Yes");
else
System.out.println("No");
}
//二分查找
static boolean binary_search(int x){
//x的存在范围是K[1],k[1+1]````k[r-1]
int l=0,r=n;
//反复操作直到存在范围位空
while(r-l>=1){
int i=(l+r)/2;//中间的数
if(k[i]==x)
return true;//找到x
else if(k[i]<x){
l=i+1;
}else{
r=i;
}
}
//没找到x
return false;
}
}
O(n^2logn)
刚刚我们只着眼于四重循环程序中最内层的循环。接下来,让我们着眼于内侧的两个循环
内侧的两个循环是在
这种情况就不能直接使用二分搜索。但是,如果预先枚举出kc+kd所得的n^2个数字并排好序,便可以利用二分搜索了
本题即需要二分搜索这一基础算法知识,也需要将两个数分为两两考虑的想象力。
package 程序设计竞赛;
import java.util.Arrays;
import java.util.Scanner;
public class 抽签¥内两层循环 {
private static int n;
private static int m;
private static int[] k;
private static int [] kk;
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc=new Scanner(System.in);
n = sc.nextInt();
m = sc.nextInt();
k = new int[n];
kk = new int[n*n];
boolean flag=false;
for(int i=0;i<n;i++){
k[i]=sc.nextInt();
}
//枚举k[c]+k[d]的和
for(int c=0;c<n;c++){
for(int d=0;d<n;d++){
kk[c*n+d]=k[c]+k[d];
}
}
//为了执行二分法查找需要先排序
Arrays.sort(kk);
for(int a=0;a<n;a++){
for(int b=0;b<n;b++){
//将内侧的两个循环替换位二分搜索
if(binary_search(m-k[a]-k[b])){
flag=true;
}
}
}
if(flag)
System.out.println("Yes");
else
System.out.println("No");
}
//二分查找
static boolean binary_search(int x){
//x的存在范围是K[1],k[1+1]````k[r-1]
int l=0,r=n*n;
//反复操作直到存在范围位空
while(r-l>=1){
int i=(l+r)/2;//中间的数
if(kk[i]==x)
return true;//找到x
else if(kk[i]<x){
l=i+1;
}else{
r=i;
}
}
//没找到x
return false;
}
}