文章目录
总结
前三题比较简单,动动脑子就可以做出来,剩下的俩有点东西。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了,不枉我做了三天。。。需要注意一下:
- 普通的26进制应该是0-25,而他这个树1-26,所以说计算高精度的时候需要把a当成0,z当成26,这两个需要特殊处理一下。需要使用高精度减法从前面一位减去。具体做法我是用Java做的(自带高精度类真香)
- 不知道为啥,使用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;
}