过完年啦,继续更新算法题,不过要复习上学期的期末考了,呜呜呜。。。。
ALGO1004-无聊的逗
资源限制
内存限制:256.0MB C/C++时间限制:1.0s Java时间限制:3.0s Python时间限制:5.0s
问题描述
逗志芃在干了很多事情后终于闲下来了,然后就陷入了深深的无聊中。不过他想到了一个游戏来使他更无聊。他拿出n个木棍,然后选出其中一些粘成一根长的,然后再选一些粘成另一个长的,他想知道在两根一样长的情况下长度最长是多少。
输入格式
第一行一个数n,表示n个棍子。第二行n个数,每个数表示一根棍子的长度。
输出格式
一个数,最大的长度。
样例输入
4
1 2 3 1
样例输出
3
数据规模和约定
n<=15
题解
使用二进制来表示木棍的选择情况。比如1000 代表只选择第一个木棍,因此我们只需要遍历以下所有情况,然后如果没有冲突的就比较出最大的值
import java.util.Scanner;
public class Main{
public static int n,mp[];
public static void main(String[] args) {
// TODO 自动生成的方法存根
Scanner cin = new Scanner(System.in);
n = cin.nextInt();
mp = new int[n+1];
for(int i = 1;i <= n;i++) {
mp[i] = cin.nextInt();
}
int status[] = new int[1<<n];
//可以用二进制表示状态 : 0001 表示用了第一根
//好了,简单明了
for(int i = 0;i<(1<<n);i++) {
for(int j = 1;j<=n;j++) {
if((i & (1<<(j-1))) > 0) {
status[i] += mp[j];
}
}
}
int ans = -9999999;
for(int i = 0;i < (1<<n);i++) {
for(int j = i + 1;j < (1<<n);j++) {
if(((i & j) == 0) && status[i] == status[j]) {
ans = Math.max(ans, status[i]);
}
}
}
System.out.println(ans);
}
}
ALGO1005-数字游戏
资源限制
内存限制:256.0MB C/C++时间限制:1.0s Java时间限制:3.0s Python时间限制:5.0s
问题描述
给定一个1~N的排列a[i],每次将相邻两个数相加,得到新序列,再对新序列重复这样的操作,显然每次得到的序列都比上一次的序列长度少1,最终只剩一个数字。
例如:
3 1 2 4
4 3 6
7 9
16
现在如果知道N和最后得到的数字sum,请求出最初序列a[i],为1~N的一个排列。若有多种答案,则输出字典序最小的那一个。数据保证有解。
输入格式
第1行为两个正整数n,sum
输出格式
一个1~N的一个排列
样例输入
4 16
样例输出
3 1 2 4
数据规模和约定
0<n<=10
题解
我们可以使用dfs抛出所有的情况,利用公式求出和即可,如果是符合的sum就返回true
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
public class Main{
public static int n,sum,flag,num[],len,num1,num2;;
public static boolean is[];
public static int C(int x,int y) {
int ans = 1;
if(y == 0) {
return ans;
}
for(int i = x;i>x-y;i--) {
ans*=i;
}
for(int i = y;i>=1;i--) {
ans/=i;
}
return ans;
}
public static boolean search() {
int number = 0;
int mid = n/2;
for(int i = 0;i<n;i++) {
if(i <= mid) {
number += (C(n-1,i)*num[i]);
}
else {
number += (C(n-1,n-i-1)*num[i]);
}
}
if(number == sum) {
return true;
}
return false;
}
public static void dfs(int cnt) {
if(flag == 1) {
return;
}
if(cnt == n) {
//已经存了四个了
if(search()) {
//如果符合条件,就Ok
flag = 1;
for(int i = 0;i<n;i++) {
System.out.print(num[i]+" ");
}
}
return;
}
if(cnt > n) {
return;
}
for(int i = 1;i<=n;i++) {
if(!is[i]) {
num[cnt] = i;
is[i] = true;
dfs(cnt+1);
is[i] = false;
}
}
}
public static void main(String[] args) {
// TODO 自动生成的方法存根
Scanner cin = new Scanner(System.in);
n = cin.nextInt();
sum = cin.nextInt();
num = new int[n];
is = new boolean[n+1];
dfs(0);
}
}
ALGO1006-拿金币
资源限制
内存限制:256.0MB C/C++时间限制:1.0s Java时间限制:3.0s Python时间限制:5.0s
问题描述
有一个N x N的方格,每一个格子都有一些金币,只要站在格子里就能拿到里面的金币。你站在最左上角的格子里,每次可以从一个格子走到它右边或下边的格子里。请问如何走才能拿到最多的金币。
输入格式
第一行输入一个正整数n。
以下n行描述该方格。金币数保证是不超过1000的正整数。
输出格式
最多能拿金币数量。
样例输入
3
1 3 3
2 2 2
3 1 2
样例输出
11
数据规模和约定
n<=1000
题解
很简单的dp递推题目,每个点只和上面和左边有关系.
import java.util.Scanner;
public class Main{
public static void main(String[] args) {
// TODO 自动生成的方法存根
Scanner cin = new Scanner(System.in);
int n = cin.nextInt();
int dp[][] = new int[n+1][n+1];
for(int i = 1;i<=n;i++) {
for(int j = 1;j<=n;j++) {
dp[i][j] = cin.nextInt();
dp[i][j] += Math.max(dp[i-1][j], dp[i][j-1]);
}
}
System.out.println(dp[n][n]);
}
}
ALGO1007-印章
资源限制
内存限制:256.0MB C/C++时间限制:1.0s Java时间限制:3.0s Python时间限制:5.0s
问题描述
共有n种图案的印章,每种图案的出现概率相同。小A买了m张印章,求小A集齐n种印章的概率。
输入格式
一行两个正整数n和m
输出格式
一个实数P表示答案,保留4位小数。
样例输入
2 3
样例输出
0.7500
数据规模和约定
1≤n,m≤20
题解
使用dp[i] [j]表示买 i 张凑齐 j 种印章的概率。
dp[i][j] = dp[i-1][j]*j*p + dp[i-1][j-1]*(n-j+1)*p;
import java.util.Arrays;
import java.util.Scanner;
public class Main{
public static void main(String[] args) {
// TODO 自动生成的方法存根
Scanner cin = new Scanner(System.in);
int n = cin.nextInt();
int m = cin.nextInt();
double p = 1.0/(n*1.0);
//保留四位小数
double dp[][] = new double[m+1][n+1];
for(double a[] : dp) {
Arrays.fill(a, 0);
}
for(int i = 1;i<=m;i++) {
for(int j = 1;j<=n;j++) {
if(i < j) {
dp[i][j] = 0;
}
else if(j == 1) {
dp[i][j] = Math.pow(p , i-1);
}
else {
dp[i][j] = dp[i-1][j]*j*p + dp[i-1][j-1]*(n-j+1)*p;
}
}
}
System.out.printf("%.4f",dp[m][n]);
}
}