hnucm_oj 算法分析与设计 练习16
问题 A:yangftc的时间安排
题目描述
yangftc需要安排他的时间,有很多事情做,每个事情都有固定的开始和结束时间,因为yangftc每次只能做一件事情,如果有两个或者多个事情的时间重合了那么他就会说 NO,否则他就会说 YES 。
输入
第一个数字t代表样例数量,
后面t个样例,每个样例输入一个n表示事情的数量,后面n行每行两个数字l r表示这个事情的开始和结束时间;
输出
判断yangftc会说什么 YES或者 NO 。
数据范围 1<=t<=500 1<=n<=100 1<=l<=r<=100000
样例输入
2
3
1 3
4 5
6 7
2
1 3
3 4
样例输出
YES
NO
#include<stdio.h>
#include<math.h>
int main()
{
int n,t,i,j,m,k;
scanf("%d",&t);
for(i=0;i<t;i++)
{
scanf("%d",&n);
int a[n],b[n];
for(j=0;j<n;j++)
{
scanf("%d %d",&a[j],&b[j]);
}
for(j=0;j<n-1;j++)
{
for(k=0;k<n-1;k++)
{
if(b[k]>b[k+1])
{
m=a[k];
a[k]=a[k+1];
a[k+1]=m;
m=b[k];
b[k]=b[k+1];
b[k+1]=m;
}
}
}
int flag=0;
for(j=0;j<n-1;j++)
{
if(b[j]>=a[j+1])
{
flag=1;
break;
}
}
if(flag==0)
{
printf("YES\n");
}
else
{
printf("NO\n");
}
}
}
问题 B:自守数
题目描述
自守数是指一个数的平方的尾数等于该数自身的自然数。例如:25^2 = 625,76^2 = 5776,9376^2 = 87909376。请求出n以内的自守数的个数。
输入
int型整数。
输出
n以内自守数的数量。
样例输入
2000
样例输出
8
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while(sc.hasNext()) {
int n =sc.nextInt();
int count = 0,flag = 0;
for(int i = 1;i<=n;i++) {
int j = i;
long a = (long)j*j;
while(j>0) {
if(j%10==a%10) {
j = j/10;
a = a/10;
flag = 1;
}
else {
flag = 0;
break;
}
}
if(flag==1) {
count++;
}
}
System.out.println(count+1);
}
}
}
问题 C: 相聚HNUCM校园食堂
题目描述
HNUCM的食堂重新装修了,小明决定约上朋友去食堂相聚,在食堂里,小明看到了M位男同学,N位女同学,小明是一个颜值控,因此他对每一位男生和女生都有一个颜值打分,他心里yy着想为这些单身狗们进行配对,小明真是一个关心同学的人!但小明认为配对同学的颜值之差不能超过5,注意必须是一位男同学和一位女同学才能配对,虽然小明对于可以配对的人数已经有了答案,但他想考考你的编程能力,因此他想请你帮他用编程算一下最多可以配对多少个人。(本题介绍仅作题目背景使用,无任何其他观点)
输入
每个测试文件仅有一条测试数据。
第一行输入M,N,分别表示男同学的数量,女同学的数量。(1<=M<=100,1<=N<=100)
第二行输入M个正整数,分别表示男同学们的颜值。
第三行输入N个正整数,分别表示女同学们的颜值。
注意,所有人的颜值分数范围在[1,100]
输出
输出最多可以配对的总人数。
样例输入
5 4
10 65 23 67 80
5 15 60 90
样例输出
4
提示
样例中第一位男同学和第一位女同学配对,第二位男同学和第三位女同学配对。
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while(sc.hasNext()) {
int m = sc.nextInt();
int n = sc.nextInt();
int[] a = new int[m];
int[] b = new int[n];
for(int i = 0;i<m;i++) {
a[i] = sc.nextInt();
}
for(int i = 0;i<n;i++) {
b[i] = sc.nextInt();
}
for(int i = 0;i<m-1;i++) {
for(int j = 0;j<m-i-1;j++) {
if(a[j]<a[j+1]) {
int t;
t = a[j];
a[j] = a[j+1];
a[j+1] = t;
}
}
}
for(int i = 0;i<n-1;i++) {
for(int j = 0;j<n-i-1;j++) {
if(b[j]<b[j+1]) {
int t;
t = b[j];
b[j] = b[j+1];
b[j+1] = t;
}
}
}
int count = 0;
for(int i = 0;i<m;i++) {
for(int j = 0;j<n;j++) {
if(Math.abs(a[i]-b[j])<=5&&a[i]!=0&&b[j]!=0) {
count++;
a[i] = 0;
b[j] = 0;
}
}
}
System.out.println(count*2);
}
}
}
问题 D: 0-1背包问题(回溯法)
题目描述
有n个物品,第i个物品重量为wi,价值为vi,现有一背包容量为C,要求把物品装入背包得到最大价值,并且要求出这些选取的物品。 要求用回溯法求解。
输入
多组测试数据,请处理到文件尾,一个整数表示物品的数量n,后一行有n个整数,代表价值,再后一行有n个整数,代表重量,最后有一个整数C代表背包容量,1<=n<=15,1<=vi<=30,1<=wi<=30,1<=C<=80。
输出
背包的最大总价值和所选取的物品,如果选取的方案有多种,请输出字典序最小的那种方案,每组测试数据应输出一行,在这里字典序最小的意思是,我们假设存在两种不同方案S,T所能得到的总价值相同且是最大的,对于方案S种选取|S|种物品,方案T选取|T|种物品,对于i=1,2…j-1,我们有si = ti,但sj < tj,则方案的S的字典序比方案T的字典序要小。由于没有使用special judge,所以如果选取得方案是S,请按照从小到大的顺序输出方案S中的物品下标。
样例输入
5
6 3 6 5 4
2 2 4 6 5
8
样例输出
15 1 2 3
import java.util.Scanner;
public class Main {
static int max,maxsort;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while(sc.hasNext()) {
int n = sc.nextInt();
int[] a = new int[n];
int[] b = new int[n];
for(int i = 0;i<n;i++) {
a[i] = sc.nextInt();
}
for(int i = 0;i<n;i++) {
b[i] = sc.nextInt();
}
int m = sc.nextInt();
max = 0;
maxsort = 10000;
int[] c = new int[n];//记录每一得到结果时的选择
int[] d = new int[n];//记录每一得到结果时的最优选择
gulu(0,0,a,b,m);
maxsort(0,0,0,a,b,c,d,m);
System.out.print(max);
for(int i = 0;i<n;i++) {
if(d[i]!=0) {
System.out.print(" ");
System.out.print(i+1);
}
}
System.out.println();
}
}
public static void gulu(int i,int p,int[] a,int[] b,int m) {
if(i<a.length) {
if(b[i]<=m) {
p = p+a[i];
m = m-b[i];
gulu(i+1,p,a,b,m);
p = p-a[i];
m = m+b[i];
}
gulu(i+1,p,a,b,m);
}
else {
if(p>max) {
max = p;
}
}
}
public static void maxsort(int i,int p,int q,int[] a,int[] b,int[] c,int[] d,int m) {
if(i<a.length) {
if(b[i]<=m) {
c[i] = 1;
p = p+a[i];
m = m-b[i];
q = q+i+1;
maxsort(i+1,p,q,a,b,c,d,m);
c[i] = 0;
p = p-a[i];
m = m+b[i];
q = q-i-1;
}
c[i] = 0;
maxsort(i+1,p,q,a,b,c,d,m);
}
else {
if(p==max) {
if(maxsort>q) {
maxsort = q;
for(int j = 0;j<a.length;j++) {
d[j] = c[j];
}
}
}
}
}
}
问题 E: 旅行售货员(TSP)
题目描述
有若干个城市,任何两个城市之间的距离都是确定的,现要求一旅行商从某城市出发必须经过每一个城市且只在一个城市逗留一次,最后回到出发的城市,问如何事先确定一条最短的线路以保证路径最短?
输入
输入两个整数n,m分别代表城市数量,边数量,2<=n<=8,n-1<=m<=2*n
接下来m行每行输入有3个整数x,y,z代表x和y城市之间有一条长为z的路,保证输入的图是连通的,旅行商总是从1城市出发。
输出
要求求出最短的路径,和该路径的长度,如果不存在这样的路径你只需要输出-1。
样例输入
4 6
1 2 30
1 3 6
1 4 4
2 3 5
2 4 10
3 4 20
样例输出
1 3 2 4 1
25
import java.util.Scanner;
public class Main {
static int max;//最优长度
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while(sc.hasNext()) {
int n = sc.nextInt();
int m = sc.nextInt();
int[][] a = new int[n][n];
int[] b = new int[n];//当前解
int[] c = new int[n];//最优解
int[] d = new int[n];//记录访问
for(int i = 0;i<m;i++) {
int j = sc.nextInt()-1;
int k = sc.nextInt()-1;
a[j][k] = sc.nextInt();
a[k][j] = a[j][k];
}
for(int i = 0;i<n;i++) {
for(int j = 0;j<n;j++) {
if(a[i][j]==0) {
a[i][j] =-1;
}
}
}
max = 10000;
d[0] = 1;
for(int i = 0;i<n;i++) {
b[i] = -1;
}
b[0] = 0;
gulu(1,0,n,a,b,c,d);
if(max==10000) {
System.out.println(-1);
}
else {
for(int i = 0;i<n;i++) {
System.out.print(c[i]+" ");
}
System.out.print("1");
System.out.println();
System.out.println(max);
}
}
}
public static void gulu(int i,int sum,int n,int[][] a,int[] b,int[] c,int[] d) {
if(i<n-1) {
for(int j = 1;j<n;j++) {
if(d[j]==0&&a[b[i-1]][j]!=-1&&sum+a[b[i-1]][j]<max) {
b[i] = j;
d[j] = 1;
sum = sum+a[b[i-1]][j];
gulu(i+1,sum,n,a,b,c,d);
sum = sum-a[b[i-1]][j];
b[i] = -1;
d[j] = 0;
}
}
}
else {
//i==n-1
for(int j = 1;j<n;j++) {
if(d[j]==0&&a[b[i-1]][j]!=-1&&a[0][j]!=-1&&sum+a[b[i-1]][j]+a[0][j]<max) {
b[i] = j;
max = sum+a[b[i-1]][j]+a[0][j];
for(int k = 0;k<n;k++) {
c[k] = b[k]+1;
}
}
}
}
}
}
问题 F: 简单递归求和
题目描述
使用递归编写一个程序求如下表达式前n项的计算结果: (n<=100)
1 - 3 + 5 - 7 + 9 - 11 +…
输入n,输出表达式的计算结果。
输入
多组输入,每组输入一个n,n<=100。
输出
输出表达式的计算结果。
样例输入
1
2
样例输出
1
-2
import java.util.Scanner;
public class Main {
static int sum;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while(sc.hasNext()) {
int n = sc.nextInt();
sum = 0;
int rel = gulu(n);
System.out.println(rel);
}
}
public static int gulu(int i) {
if(i==1) {
return 1;
}
else {
int a = 2*i-1;
if(i%2==0) {
return gulu(i-1)-a;
}
else {
return gulu(i-1)+a;
}
}
}
}
问题 G: 文件存储
题目描述
如果有n个文件{F1,F2,F3,…,Fn}需要存放在大小为M的U盘中,文件i的大小为Si,1<=i<=n。请设计一个算法来提供一个存储方案,使得U盘中存储的文件数量最多。
输入
多组输入,对于每组测试数据,每1行的第1个数字表示U盘的容量M(以MB为单位,不超过256*1000MB),第2个数字表示待存储的文件个数n。
第2行表示待存储的n个文件的大小(以MB为单位)。
输出
输出最多可以存放的文件个数。
样例输入
10000 5
2000 1000 5000 3000 4000
样例输出
4
import java.util.Scanner;
public class Main {
static int sum;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while(sc.hasNext()) {
int m = sc.nextInt();
int n = sc.nextInt();
int[] a = new int[n];
int count = 0;
for(int i = 0;i<n;i++) {
a[i] = sc.nextInt();
}
for(int i = 0;i<n-1;i++) {
for(int j = 0;j<n-1-i;j++) {
if(a[j]>a[j+1]) {
int t;
t = a[j];
a[j] = a[j+1];
a[j+1] = t;
}
}
}
for(int i =0;i<n;i++) {
if(m>=a[i]) {
count++;
m = m-a[i];
}
else {
break;
}
}
System.out.println(count);
}
}
}
问题 H: 递归求和
题目描述
使用递归编写一个程序求如下表达式的计算结果: (1<n<=20)
S(n) = 14 + 49 + 916 + 1625 + … + ((n-1)2)*n2
输入n,输出表达式S(n)的结果。
输入
单组输入,输入一个正整数n,1<n<=20。
输出
输出表达式S(n)的计算结果。
样例输入
3
样例输出
40
import java.util.Scanner;
public class Main {
static int sum;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int rel = gulu(n);
System.out.println(rel);
}
public static int gulu(int i) {
if(i==2) {
return 4;
}
else {
return gulu(i-1)+(i-1)*(i-1)*i*i;
}
}
}
问题 I: 最大收益
题目描述
小X是一位精明的投资人,他每次都能够做出正确的投资判断。
现在有N个项目,每个项目的总投资额和总收益已知,并且每一个项目都允许小X只投资一部分,当然也就只能拿到一部分收益。
现在小X决定拿出M万元钱来进行投资,请你帮他设计一个算法来计算最大收益和。
输入
单组输入,对于每一组数据,第1行包含两个正整数,分别是M和N,其中M<=10^6,N<=100。
接下来N行每行均包含两个正数(不一定是正整数),第1数字表示第N个项目的总投资额(万元),第2个数字表示第N个项目的总收益(万元),两个数字之间用空格隔开。
输出
小X可以获得的最大收益和(万元,结果四舍五入保留两位小数)。
样例输入
100 4
50 10
20 10
40 10
50 20
样例输出
37.50
import java.text.DecimalFormat;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while(sc.hasNext()) {
double m = sc.nextDouble();
int n = sc.nextInt();
double[] a = new double[n];
double[] b = new double[n];
double[] c = new double[n];
double v = 0;
for(int i = 0;i<n;i++) {
a[i] = sc.nextDouble();
b[i] = sc.nextDouble();
c[i] = b[i]/a[i];
}
for(int i = 0;i<n-1;i++) {
for(int j = 0;j<n-i-1;j++) {
if(c[j]<c[j+1]) {
double t;
t = a[j];
a[j] = a[j+1];
a[j+1] = t;
t = b[j];
b[j] = b[j+1];
b[j+1] = t;
t = c[j];
c[j] = c[j+1];
c[j+1] = t;
}
}
}
int i;
for(i = 0;i<n;i++) {
if(m>=a[i]) {
v = v+b[i];
m = m-a[i];
}
else {
break;
}
}
if(i!=n) {
v = v+m*c[i];
}
String vv = new DecimalFormat("#.00").format(v);
System.out.println(vv);
}
}
}
问题 J: 排列蛋卷
题目描述
刚考完研的TC同学这段时间在家闲得慌,因此他决定学点新手艺。今天他学习的内容是:做蛋卷。
由于是第一次做蛋卷,TC同学做出来蛋卷长短不一。看着这些长度都不一样的蛋卷,TC同学的强迫症又犯了。他希望能够拿出其中部分蛋卷,使得留下来的蛋卷能够按照长度从大到小的次序排列。
请问他最少需要拿出多少根蛋卷?
输入
单组输入,对于每一组测试数据,第1行N表示蛋卷的总数量(n<=1000)。
第2行包含N个正整数,分别表示每一根蛋卷的长度。(单位:厘米)
保证在同一组输入数据中每一根蛋卷的长度均不一样。
输出
输出最少需要拿出的蛋卷数量。
样例输入
5
15 18 17 11 12
样例输出
2
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while(sc.hasNext()) {
int n = sc.nextInt();
int[] a = new int[n];
int[] b = new int[n];//记录
int maxLen = 0;
for(int i=0;i<n;i++) {
a[i] = sc.nextInt();
}
b[0] = 1;
for(int i=1;i<n;i++) {
int max = 0;
for(int j = i-1;j>=0;j--) {
if(a[i]<a[j]&&b[j]>max) {
max = b[j];
}
}
b[i] = max+1;
if(maxLen<b[i]) {
maxLen = b[i];
}
}
System.out.println(n-maxLen);
}
}
}
PS:这周的题是真难。。。