【搜索】C_LG_世界冰球锦标赛(暴搜 / 01 dp / 折半暴搜)

一、Problem

今年的世界冰球锦标赛在捷克举行。Bobek 已经抵达布拉格,他不是任何团队的粉丝,也没有时间观念。他只是单纯的想去看几场比赛。如果他有足够的钱,他会去看所有的比赛。不幸的是,他的财产十分有限,他决定把所有财产都用来买门票。

给出 Bobek 的预算和每场比赛的票价,试求:如果总票价不超过预算,他有多少种观赛方案。如果存在以其中一种方案观看某场比赛而另一种方案不观看,则认为这两种方案不同。

输入格式:

第一行,两个正整数 N 和 M(1≤N≤40,1≤M≤1018),表示比赛的个数和 Bobek 那家徒四壁的财产。

第二行,N 个以空格分隔的正整数,均不超过 1016,代表每场比赛门票的价格。

输出格式:

输出一行,表示方案的个数。由于 N 十分大,注意:答案 ≤ 240。

输入输出样例

输入样例#1:
5 1000
100 1500 500 500 1000
输出样例#1:
8

样例解释

八种方案分别是:

  • 一场都不看,溜了溜了
  • 价格 100 的比赛
  • 第一场价格 500 的比赛
  • 第二场价格 500 的比赛
  • 价格 100 的比赛和第一场价格 500 的比赛
  • 价格 100 的比赛和第二场价格 500 的比赛
  • 两场价格 500 的比赛
  • 价格 1000 的比赛

有十组数据,每通过一组数据你可以获得 10 分。各组数据的数据范围如下表所示:
在这里插入图片描述

二、Solution

比赛的个数正常,但是财产最大有 1 0 18 10^{18} ,dp 数组也不可能开这么大…不然可以用 01 dp 把它 A 掉…

方法一:暴搜

  • 对于某一场比赛,可看可不看…
  • 最后遍历到最后一场比赛,res++

超时与溢出:16/100 分…

import java.util.*;
import java.math.*;
import java.io.*;
public class Main{
	static class Solution {
		int N;
		long[] a;
		long res;
		void dfs(int k, long m) {
			if (m < 0)
				return;
			if (k == N) {
				res++;
				return;
			}
			dfs(k+1, m);
			dfs(k+1, m-a[k]);
		}
		void init() {
			Scanner sc = new Scanner(new BufferedInputStream(System.in));
			N = sc.nextInt();
			int M = sc.nextInt();
			a = new long[N];
			for (int i = 0; i < N; i++) {
				a[i] = sc.nextLong();
			}
			dfs(0, M);
			System.out.println(res);
		}
	}
    public static void main(String[] args) throws IOException {  
        Solution s = new Solution();
		s.init();
    }
}

复杂度分析

  • 时间复杂度: O ( 2 N ) O(2^N)
  • 空间复杂度: O ( . . . ) O(...)

方法二:01 背包

  • 定义状态
    • 场次为 i d p [ j ] i,dp[j] 表示余额为 j 时,不考虑第 i 场比赛的方案数。
    • 相反也很简单…
  • 思考状态转移方程
    • 场次为 i,余额为 j 时, d p [ j ] = d p [ j ] + d p [ j a [ i ] ] dp[j] = dp[j] + dp[j-a[i]] ,当余额为 j 时,我可选择看或不看第 i 场比赛…
  • 思考初始化:
    • dp[0] = 1,表示余额为 0 时,不看也是一种方案。
  • 思考输出 s u m ( d p [ 0... m ] ) sum(dp[0...m]) 表示方案数位余额为 0 m 0-m 时的方案数之和。

溢出:32 分…

import java.util.*;
import java.math.*;
import java.io.*;
public class Main{
	static class Solution {
		void init() {
			Scanner sc = new Scanner(new BufferedInputStream(System.in));
			int N = sc.nextInt();
			int m = sc.nextInt();
			int[] a = new int[N+1];
			long res = 0;
			for (int i = 1; i <= N; i++) {
				a[i] = sc.nextInt();
			}
			int[] dp = new int[m+1];
			dp[0] = 1;
			for (int i = 1; i <= N; i++) {
				for (int j = m; j >= a[i]; j--)
					dp[j] = dp[j] + dp[j-a[i]];
			}
			for (int i = 0; i <= m; i++)
				res += dp[i];
			System.out.println(res);
		}
	}
    public static void main(String[] args) throws IOException {  
        Solution s = new Solution();
		s.init();
    }
}

复杂度分析

  • 时间复杂度: O ( n ) O(n)
  • 空间复杂度: O ( n ) O(n)

方法三:折半搜索

原创文章 787 获赞 314 访问量 5万+

猜你喜欢

转载自blog.csdn.net/qq_43539599/article/details/105868489