2021.07.11_ACM暑假集训前第一次比赛

本次ACM暑假集训前的比赛中,涉及了计算两点间距离、电话号码列表比较、斐波那契数列、26进制与十进制转化及胜利大逃亡等题目。对于D题和E题,需要使用高精度运算和广搜算法,作者在赛后补充了D题的Java版AC代码。
摘要由CSDN通过智能技术生成

总结

前三题比较简单,动动脑子就可以做出来,剩下的俩有点东西。D题需要使用高精,E题需要使用搜索,需要学习相关算法才能做…嗯,下次一定下次一定(逃~)

A - 计算两点间的距离 HDU - 2001

题目

在这里插入图片描述

思路

签到题,根据两点之间距离公式计算出值即可,没啥好说的

代码

#include<iostream>
#include<math.h>
using namespace std;
int main() {
    float x1,x2,y1,y2;
    float t1,t2;
    while(scanf("%f %f %f %f",&x1,&x2,&y1,&y2) != EOF) {
        t1=y1-x1;
        t2=y2-x2;
        printf("%.2f\n",sqrt(t1*t1 + t2*t2));
    }
    return 0;
}

B - Phone List HDU - 1671

题目

在这里插入图片描述

思路

这道题没做出来,当时使用for嵌套超时了。后期百度后发现非常简单,使用字典序排序后前缀相同的必定相邻,所以只需要比较相邻的字符串即可。当时使用Java写的,使用C++同理,等价于使用sort函数重写compare()函数实现字符串字典序排序。

代码

import java.util.*;
public class Test {
    public static void main(String[] args) {
        boolean m;
        List<String> list = new ArrayList<>();	//创建String类型的List容器
        Scanner sc = new Scanner(System.in);
        String str;
        int t,n;
        t=sc.nextInt();					//输入t
        while(t-- > 0){
            m = true;
            n=sc.nextInt();				//输入n
            for(int i = 0;i<n;i++){
                str = sc.next();		//输入字符串并保存到str
                list.add(str);			//将字符串添加到list容器种
            }
            Collections.sort(list, new Comparator<String>() {	//调用Collection的sort()方法对list排序,同时重写Comparator中的compare()方法使其可以对字符串进行字典序升序排序
                @Override
                public int compare(String o1, String o2) {
                    char[] chars1 = o1.toCharArray();
                    char[] chars2 = o2.toCharArray();
                    int i=0;
                    while(i<chars1.length && i< chars2.length){
                        if(chars1[i] > chars2[i]){
                            return 1;
                        }else if(chars1[i] < chars2[i]){
                            return -1;
                        }else{
                            i++;
                        }
                        if(i==chars1.length){
                            return -1;
                        }
                        if(i==chars2.length){
                            return 1;
                        }
                    }
                    return 0;
                }
            });
            /*
            for(String l:list)			//使用foreach遍历list容器,检查排序是否正确
                System.out.println(l);
            */
            for(int i=0;i<n-1;i++){
                String s1=list.get(i);		//获取容器内第i个字符串
                String s2=list.get(i+1);	//获取容器内第i+1个字符串
                int k = s1.length();		//获取s1的长度
                int p = s2.length();		//获取s2的长度
                if(p<k)						//若前者长度比后者大,前者不可能是后者的前缀,直接跳过
                    continue;
                if(s1.equals(s2.substring(0,k))){	//比较第一个字符串是否和第二个字符串的前k个字符相同
                    m=false;
                    break;
                }
            }
            if(m){
                System.out.println("YES");
            }else{
                System.out.println("NO");
            }
            list.clear();					//清空容器,为下次程序运行做准备
        }

    }
}

C - 一只小蜜蜂… HDU - 2044

题目

在这里插入图片描述

思路

蜜蜂每次仅可以从前一个蜂房和前两个蜂房爬过来,所以f(n) = f(n-1)+f(n-2),感觉眼熟不?这不就是斐波那契数列么…只不过开始的时候和斐波那契数列不同,我们对前三个数据进行初始化即可:f[1] = 0,f[2] = 1,f[3] = 2,蜜蜂从a蜂房到b蜂房的各种可能路径,相当于从第1蜂房到第b-a+1蜂房。还有需要注意的一点是b的最大取值是50,所以需要开long long的数组才可以。

代码

#include<iostream>
void fun(void);
using namespace std;
long long int fn[51]={0,0,1,2};		//初始化
int main() {
    fun();
    int n, a, b;
    cin >> n;
    while(n--) {
        cin >> a >> b;
        cout << fn[b-a+1] << endl;
    }
    return 0;
}
void fun(void) {					//离线计算50个斐波那契的值
    for(int i=4;i<=50;i++)
        fn[i] = fn[i-1] + fn[i-2];
}

D - Numerically Speaking HDU - 1314

题目

在这里插入图片描述

思路

本题是26进制与十进制之间的转化,需要使用高精完成
咳,由于本人较菜,先把答案代码沾上,挖个坑,有时间再回来看 =.=

代码

#include <iostream>
#include<cstring>
char str[101];
char answer[101];
int  number[101];
int main() {
    while (~scanf("%s",str)) {
        if (strcmp(str, "*")) {
            int base_from, base_to, length = strlen(str);
            if (str[0] >= '0' && str[0] <= '9') {
                base_from = 10;
                base_to = 26;
                for (int i = 0; i < length; ++ i)
                    number[i] = str[length-1-i]-'0';
            }
            else {
                base_from = 26;
                base_to = 10;
                for (int i = 0; i < length; ++ i)
                    number[i] = str[length-1-i]-'a'+1;
            }
            int loop = length*2;
            for (int i = 0; i < loop; ++ i) {
                int left = 0;
                for (int j = length; j >= 0; -- j) {
                    left = left*base_from + number[j];
                    number[j] = left/base_to;
                    left = left%base_to;
                }
                answer[i] = left;
                for (int j = 0; j < loop; ++ j) {
                    if (number[j] >= base_from) {
                        number[j+1] = number[j+1] + number[j]/base_from;
                        number[j] = number[j]%base_from;
                    }
                }
            }
            int save = loop-1;
            while (!answer[save])
                save --;
            if (base_to == 10)
                printf("%-22s",str);
            for (int i = save; i >= 0; -- i) {
                if (base_to == 26)
                    printf("%c",answer[i]+'a'-1);
                else {
                    printf("%c",answer[i]+'0');
                    if (i > 0 && i%3 == 0)
                        printf(",");
                }
            }
            if (base_to == 26) {
                for (int j = save; j < 21; ++ j)
                    printf(" ");
                for (int j = 0; j < length; ++ j) {
                    printf("%c",str[j]);
                    if (length-1 > j && (length-j)%3 == 1)
                        printf(",");
                }
            }
            puts("");
        }
    }
    return 0;
}

填坑-2021.07.29

完全自己做的题目终于AC了,不枉我做了三天。。。需要注意一下:

  1. 普通的26进制应该是0-25,而他这个树1-26,所以说计算高精度的时候需要把a当成0,z当成26,这两个需要特殊处理一下。需要使用高精度减法从前面一位减去。具体做法我是用Java做的(自带高精度类真香)
  2. 不知道为啥,使用System.out.printf("%-22s%s")提交后报格式错误,俺也不晓得哪里不对,最后自己写了个print方法搞定

填坑的Numerically Speaking HDU - 1314解题代码(Java版AC代码)

package Test;
import java.io.*;
import java.util.*;
import java.math.*;
public class Test01 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(new BufferedInputStream(System.in));
        while(true){
            StringBuffer str = new StringBuffer(scanner.next());
            if(str.toString().equals("*"))
                break;
            if(str.charAt(0) < 'a'){
                BigInteger x = new BigInteger(str.toString());
                StringBuffer strb = new StringBuffer();
                BigInteger[] t = x.divideAndRemainder(BigInteger.valueOf(26));
                if(t[1].compareTo(BigInteger.valueOf(0)) == 0 ){
                    strb.append('z');
                    t[0] = t[0].subtract(BigInteger.valueOf(1));
                }else{
                    strb.append((char)('a' + t[1].intValue() - 1));
                }
                while(t[0].compareTo(BigInteger.valueOf(0)) != 0){
                    t = t[0].divideAndRemainder(BigInteger.valueOf(26));
                    if(t[1].compareTo(BigInteger.valueOf(0)) == 0 ){
                        strb.append('z');
                        t[0] = t[0].subtract(BigInteger.valueOf(1));
                    }else{
                        strb.append((char)('a' + t[1].intValue() - 1));
                    }
                }
                print(strb.reverse().toString(),x.toString());
            }else{
                StringBuffer strb = new StringBuffer(str);
                BigInteger big = new BigInteger("0");
                strb.reverse();
                for(int i=0;i<strb.length();i++){
                    big = big.add(BigInteger.valueOf(26).pow(i).multiply(BigInteger.valueOf(strb.charAt(i)-'a'+1)));
                }
                print(strb.reverse().toString(),big.toString());
            }
        }
    }
    public static void print(String str,String num){
        char[] chstr;
        chstr = str.toCharArray();
        int t = str.length();
        for(int i=0;i<22;i++){
            if(i<t)
                System.out.print(chstr[i]);
            else
                System.out.print(" ");
        }
        char[] chnum = num.toCharArray();
        int len = num.length();
        int first = len%3-1;
        for(int i=0;i<len;i++){
            System.out.print(chnum[i]);
            if( (i-first)%3==0 && i!=len-1 ) {
                System.out.print(",");
            }
        }
        System.out.println();
    }
}

E - 胜利大逃亡 HDU - 1253

题目

在这里插入图片描述

思路

。。。
依然复制粘贴的答案

因为要求"最少"之类的,所以很容易想到广搜,没错,这是 bfs 的裸题,只是它的状态数是个三维数组,转移的状态(方向)也从二维数组的4个变成了6个而已,但原理是一样的,直接广搜即可,只是这题的坑未免也太不人性化了,我 wa了几发看了讨论区后才知道原来起点不管是不是墙都不用管(继续搜),只需看终点即可。

用个三维的 dp 数组来记录从起点出发到当前结点的时间/步数

代码

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<queue>
using namespace std;
#define For(i,s,t)    for(int i=s; i<t; ++i)
const int inf= 0x2fffffff;
int a,b,c,T;
int f[60][60][60], dp[60][60][60];
int dir[8][3]= {{0,0,1},{0,1,0},{-1,0,0},{1,0,0},{0,-1,0},{0,0,-1}};
struct node {
    int x,y,z;
    node(int x=0, int y=0, int z=0): x(x),y(y),z(z) {}
};
void solve() {
    scanf("%d%d%d%d",&a,&b,&c,&T);
    For(i,0,a+2)    For(j,0,b+2)    For(k,0,c+2) {
        f[i][j][k]= 1;
        dp[i][j][k]= inf;
    }
    For(i,1,a+1)    For(j,1,b+1)    For(k,1,c+1)
    scanf("%d",f[i][j]+k);
    //如果终点是墙就永远出不了
    //或者从起点到终点的最短直线距离比 T大的话也出不了,是个很重要的剪枝
    if(f[a][b][c]==1 || a+b+c-3 > T) {
        puts("-1");
        return ;
    }
    queue<node> q;
    q.push(node(1,1,1));
    dp[1][1][1]= 0;
    while(q.size()) {
        node p= q.front();
        q.pop();
        for(int k=0; k<6; ++k) {
            int dx= p.x+dir[k][0], dy= p.y+dir[k][1], dz= p.z+dir[k][2];
            if(f[dx][dy][dz]!= 1 && dp[dx][dy][dz]== inf) {
                dp[dx][dy][dz]= dp[p.x][p.y][p.z]+1;
                q.push(node(dx,dy,dz));
            }
        }
    }
    //算出到达终点的时间后,还需判断是否满足题意
    if(dp[a][b][c] > T)      puts("-1");
    else    printf("%d\n",dp[a][b][c]);
}
int main() {
    int k;
    scanf("%d",&k);
    while(k--)    solve();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值