hnucm-oj1171 - 2021年春季学期《算法分析与设计》练习6
A 1420: 数组合并
题目描述
编写一个程序,将两个有序数组合并成一个更大的有序数组,要求时间复杂度为O(n)。
输入
多组数据输入,每组输入包括两行,每行第一个数字为数组长度n,然后输入n个有序整数。
输出
输出合并后的数组(升序),每组输出用一个空行隔开。
样例输入 Copy
3 1 3 5
3 2 4 6
2 1 2
4 3 4 5 6
样例输出 Copy
1 2 3 4 5 6
1 2 3 4 5 6
#include <stdio.h>
#include <stdlib.h>
void merge(int sr[],int tr[],int s,int m,int t){
int i=s,j=m+1,k=s;
while(i<=m&&j<=t){
if(sr[i]<=sr[j])
tr[k++]=sr[i++];
else
tr[k++]=sr[j++];
}
while(i<=m)
tr[k++]=sr[i++];
while(j<=t)
tr[k++]=sr[j++];
}
void mergesort(int sr[],int s,int t){
int tr[t+1];
if(s<t){
int m=(s+t)/2;
mergesort(sr,s,m);
mergesort(sr,m+1,t);
merge(sr,tr,s,m,t);
for(int i=s;i<=t;i++)
sr[i]=tr[i];
}
}
int main(){
int a,b,i,j;
while(scanf("%d",&a)!=EOF){
int m[a];
for(i=0;i<a;i++)
scanf("%d",&m[i]);
scanf("%d",&b);
int n[b];
for(i=0;i<b;i++)
scanf("%d",&n[i]);
int p=a+b;
int sr[p],tr[p];
for(i=0;i<a;i++)
sr[i]=m[i];
for(i=0;i<b;i++)
sr[i+a]=n[i];
mergesort(sr,0,p-1);
for(i=0;i<p;i++){
printf("%d ",sr[i]);
}
printf("\n");
printf("\n");
}
}
B 1421: 归并排序
题目描述
编写一个程序,使用分治策略实现二路归并排序(升序)。
输入
多组输入,每组第一个数字为数组长度,然后输入一个一维整型数组。
输出
输出排序之后(升序)的一维整型数组,每组输出占一行。
样例输入 Copy
6 1 8 6 5 3 4
5 12 42 2 5 8
样例输出 Copy
1 3 4 5 6 8
2 5 8 12 42
#include <stdio.h>
#include <stdlib.h>
void merge(int sr[],int tr[],int s,int m,int t){
int i=s,j=m+1,k=s;
while(i<=m&&j<=t){
if(sr[i]<=sr[j])
tr[k++]=sr[i++];
else
tr[k++]=sr[j++];
}
while(i<=m)
tr[k++]=sr[i++];
while(j<=t)
tr[k++]=sr[j++];
}
void mergesort(int sr[],int s,int t){
int tr[t+1];
if(s<t){
int m=(s+t)/2;
mergesort(sr,s,m);
mergesort(sr,m+1,t);
merge(sr,tr,s,m,t);
for(int i=s;i<=t;i++)
sr[i]=tr[i];
}
}
int main(){
int a,b,i,j;
while(scanf("%d",&a)!=EOF){
int m[a];
for(i=0;i<a;i++)
scanf("%d",&m[i]);
mergesort(m,0,a-1);
for(i=0;i<a;i++){
printf("%d ",m[i]);
}
printf("\n");
}
}
C 1677: 第k小元素问题
题目描述
输入一个整数数组,请求出该数组的第k小元素。要求时间复杂度为O(n)。
输入
每组输入包括两行,第一行为一个整数数组,两个数字之间用空格隔开;第二行为k值。数组中元素个数小于10^9。
输出
输出第k小元素的值。
样例输入 Copy
2 5 6 1 8 7 9
2
样例输出 Copy
2
import java.util.Scanner;
public class Main {
static void swap(int a[],int i,int j){
int t;
t=a[i];
a[i]=a[j];
a[j]=t;
}
public static int partition(int a[],int p,int q){
int x=a[p],i=p,j;
for(j=p+1;j<=q;j++){
if(a[j]<=x){
i++;
swap(a,i,j);
}
}
swap(a,p,i);
return i;
}
public static int quickselect(int a[],int s,int t,int k) {
if(s==t)
return a[s];
int i=partition(a,s,t);
int j=i-s+1;
if(k<=j)
return quickselect(a,s,i,k);
else
return quickselect(a,i+1,t,k-j);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner scan=new Scanner(System.in);
while(scan.hasNextInt()) {
String str1=scan.nextLine();
String str2=scan.nextLine();
int k=Integer.parseInt(str2);
String[] str=str1.split(" ");
int[] a=new int[str.length];
for(int i=0;i<a.length;i++) {
a[i]=Integer.parseInt(str[i]);
}
int res=quickselect(a,0,a.length-1,k);
System.out.println(res);
}
}
}
D 1668: 找中位数
题目描述
请设计一个算法,不排序,快速计算出一个无序数列的中位数。 时间复杂度要求为O(n)。
如果有奇数个元素,中位数则是数组排序后最中间的那个数字。
如果是偶数个元素,中位数则是数组排序后最中间两个元素的平均值。
输入
有多组输入,每组输入的第一行为n(1<=n<=1e5),表示该数列的元素个数。
第二行为n个整数组成的无序数列
输出
每组样例输出一行,表示该无序数列的中位数。
若为偶数,请保留三位小数
若为奇数,直接输出
样例输入 Copy
5
5 3 2 1 4
样例输出 Copy
3
import java.text.DecimalFormat;
import java.util.Scanner;
public class Main {
static void swap(int a[],int i,int j){
int t;
t=a[i];
a[i]=a[j];
a[j]=t;
}
public static int partition(int a[],int p,int q){
int x=a[p],i=p,j;
for(j=p+1;j<q;j++){
if(a[j]<=x){
i++;
swap(a,i,j);
}
}
swap(a,p,i);
return i;
}
public static int quickselect(int a[],int s,int t,int k) {
if(s==t)
return a[s];
int i=partition(a,s,t);
int j=i-s+1;
if(k<=j)
return quickselect(a,s,i,k);
else
return quickselect(a,i+1,t,k-j);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner scan=new Scanner(System.in);
while(scan.hasNextInt()) {
int k=scan.nextInt();
int[] a=new int[k];
for(int i=0;i<a.length;i++) {
a[i]=scan.nextInt();
}
if(k%2!=0) {
int res1=quickselect(a,0,k-1,k/2+1);
System.out.println(res1);
}
else {
int m=quickselect(a,0,k,k/2);
int n=quickselect(a,0,k,k/2+1);
double res2=(m+n)/2.0;
DecimalFormat df2 = new DecimalFormat("###.000");
System.out.println(df2.format(res2));
}
}
}
}
E 1422: 棋盘覆盖问题
题目描述
在一个n×n (n = 2k)个方格组成的棋盘中,恰有一个方格与其他方格不同,称该方格为一特殊方格,且称该棋盘为一特殊棋盘。
在棋盘覆盖问题中,要用图示的4种不同形态的L型骨牌覆盖给定的特殊棋盘上除特殊方格以外的所有方格,且任何2个L型骨牌不得重叠覆盖。
输入
多组测试用例,每组测试用例包括两部分,
第一部分为方格的宽度n,
第二部分则为方格,特殊方格为-1,其他方格为0。
输出
输出覆盖后的方案
样例输入 Copy
4
-1 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
样例输出 Copy
-1 2 4 4
2 2 1 4
3 1 1 5
3 3 5 5
#include <stdio.h>
#include <stdlib.h>
int flag=1;
int a[1000][1000]={0};
void f(int tr,int tc,int dr,int dc,int n){
if(n==1)
return ;
int t=flag++;
int s=n/2;
//左上角
if(dr<tr+s&&dc<tc+s)
f(tr,tc,dr,dc,s);
else{
a[tr+s-1][tc+s-1]=t;
f(tr,tc,tr+s-1,tc+s-1,s);
}
//左下角
if(dr>=tr+s&&dc<tc+s)
f(tr+s,tc,dr,dc,s);
else{
a[tr+s][tc+s-1]=t;
f(tr+s,tc,tr+s,tc+s-1,s);
}
//右上角
if(dr<tr+s&&dc>=tc+s)
f(tr,tc+s,dr,dc,s);
else{
a[tr+s-1][tc+s]=t;
f(tr,tc+s,tr+s-1,tc+s,s);
}
//右下角
if(dr>=tr+s&&dc>=tc+s)
f(tr+s,tc+s,dr,dc,s);
else{
a[tr+s][tc+s]=t;
f(tr+s,tc+s,tr+s,tc+s,s);
}
}
int main(){
int n,i,j,p,q;
while(scanf("%d",&n)!=EOF)
{
flag=1;
for(i=0;i<n;i++){
for(j=0;j<n;j++)
{
scanf("%d",&a[i][j]);
if(a[i][j]==-1){
p=i;
q=j;
}
}
}
f(0,0,p,q,n);
for(i=0;i<n;i++){
for(j=0;j<n;j++)
{
printf("%d ",a[i][j]);
}
printf("\n");
}
}
}
F 1445: 大整数乘法
题目描述
使用分治算法实现两个大整数相乘。
输入
两个十进制大整数,满足每一个整数长度为2^n且两个大整数的长度相等。(多组数据)
输出
两个大整数的乘积。
样例输入 Copy
1234 5678
样例输出 Copy
7006652
#include <stdio.h>
#include <stdlib.h>
#include<math.h>
int sign(long value){
int a;
if(value>0)
a=1;
else
a=-1;
return a;
}
long fun(long a,long b,int n){
int s=sign(a)*sign(b);
a=abs(a);
b=abs(b);
long mul;
if(a==0||b==0)
mul=0;
else if(n==1)
mul=s*a*b;
else{
long A1=(long)(a/pow(10,n/2));
long B1=(a%(long)pow(10,n/2));
long A2=(long)(b/pow(10,n/2));
long B2=(b%(long)pow(10,n/2));
long A=fun(A1,A2,n/2);
long B=fun(B1,B2,n/2);
long AB=fun((A1-B1),(B2-A2),n/2)+A+B;
mul=(long)(s*(A*pow(10,n)+AB*pow(10,n/2)+B));
}
return mul;
}
int main(){
long a,b;
while(scanf("%ld%ld",&a,&b)!=EOF){
int m=a;
int flag=0;
while(m!=0){
m=m/10;
flag++;
}
printf("%ld\n",fun(a,b,flag));
}
}