【题目描述】
暴力枚举 迭代写法
【思路】
分别枚举m、n的个数
for(m个数)
for(n个数)
k = m * m个数 + n * n个数
O(N^2),只能枚举答案在1000以内的
import java.util.Scanner;
public class Main{
static int N = 10010;
static int []f = new int [N];
public static void main(String args[]){
Scanner reader = new Scanner(System.in);
int n = reader.nextInt(), m = reader.nextInt();
for(int i = 0; i < N / m + 1; i ++)//枚举m的个数
for(int j = 0; j < N / n + 1; j++)//枚举n的个数
{
int k = m * i + n * j;
if( k >= N ) continue;
f[k] = 1;
}
for(int i = N - 1; i >= 0;i --)
if(f[i] == 0){
System.out.println(i);
break;
}
}
}
暴力枚举——递归写法
过5/10数据
import java.util.Scanner;
public class Main{
//判断x能否由m、n组成
public static boolean dfs(int x, int m, int n){
if( x < 0) return false;
//x == 0 说明x能由若干m、n组成
if( x == 0 ) return true;
if( x >= m && dfs(x - m, m, n)) return true;
if( x >= n && dfs(x - n, m, n)) return true;
return false;
}
public static void main(String args[]){
Scanner reader = new Scanner(System.in);
int m = reader.nextInt(), n = reader.nextInt();
for(int i = 1000; i >= 1; i --)
{
if(!dfs(i, m, n)){
System.out.println(i);
break;
}
}
}
}
错误写法:
对于有返回值的递归函数,要注意对中间结果的保存和处理,只是把它扔掉了
import java.util.Scanner;
public class Main{
//判断x能否由m、n组成
public static boolean dfs(int x, int m, int n){
if( x < 0) return false;
//x == 0 说明x能由若干m、n组成
if( x == 0 ) return true;
if( x >= m ) return dfs(x - m, m, n);
if( x >= n ) return dfs(x - n, m, n);
return false;
}
public static void main(String args[]){
Scanner reader = new Scanner(System.in);
int m = reader.nextInt(), n = reader.nextInt();
for(int i = 1000; i >= 1; i --)
{
if(!dfs(i, m, n)){
System.out.println(i);
break;
}
}
}
}
AC代码
两个数xy如果互质,那么最大不能组成的数是xy-x-y,如果两个数不互质能组成任何数。这题比较考验数学思维。
引理
给定a,b,如果d =gcd(a, b) >1,那么其凡不是d倍数的a,b都凑不出,因此其凑不出来的数目是INF个。
结论
若a、b均为正整数且gcd(a,b) = 1, 那么 ax + by ,x >= 0, y >= 0,最大不能表示的数为 (a - 1) * (b - 1) = a*b - a - b
import java.util.Scanner;
public class Main{
public static void main(String args[]){
Scanner reader = new Scanner(System.in);
int a = reader.nextInt(), b = reader.nextInt();
//公式: (a - 1) * (b - 1) - 1 =ab -a - b
System.out.println(a * b - a - b);
}
}
包子凑数
import java.util.Scanner;
class Main{
static int N = 110, M = 10000;
static int a[] = new int [N];
static boolean f[][] = new boolean[N][M];
static int gcd(int a, int b){
if(b == 0) {return a;}
return gcd(b, a % b);
}
public static void main(String args[]){
Scanner reader = new Scanner(System.in);
int n = reader.nextInt();
for(int i = 1; i <= n; i ++) {
a[i] = reader.nextInt();
}
int d = 0;
for(int i = 1; i <= n; i ++){
d = gcd(d, a[i]);
}
if(d != 1) {
System.out.println("INF");
}else{
// 0个物品,重量为0,合法方案
f[0][0] = true;
for(int i = 1; i <= n; i ++){
for(int j = 0; j < M; j ++){
f[i][j] = f[i - 1][j];
for(int k = 0; k * a[i] <= j; k ++){
f[i][j] |= f[i - 1][j - k * a[i]];
}
}
}
int res = 0;
for(int j = 1; j < M; j ++){
if(!f[n][j]){
res ++;
// System.out.println(j);
}
}
System.out.println(res);
}
}
}
import java.util.Scanner;
class Main{
static int N = 10010;
static int a[] = new int[110];
static boolean f[][] = new boolean [110][N];
public static int gcd(int a, int b){
if( b == 0) return a;
return gcd( b, a % b );
}
public static void main(String args[]){
Scanner reader = new Scanner(System.in);
int n = reader.nextInt();
for(int i = 1; i <= n; i ++) a[i] = reader.nextInt();
int d = 0; // 公约数
for(int i = 1; i <= n; i ++)
d = gcd(a[i], d); //gcd(2,0) = 2
if( d != 1) System.out.println("INF");
else{
f[0][0] = true;
for(int i = 1; i <= n; i ++)
for(int j = 0; j < N; j ++){
f[i][j] |= f[i - 1][j];
if( j >= a[i]) f[i][j] |= f[i][j - a[i]];
}
int res = 0;
for(int i = 1; i < N; i ++)
if( ! f[n][i] ) res ++;
System.out.println(res);
}
}
}