【算法】【PAT】1031-1040

点击前往【PAT甲级之路总纲】

1031 Hello World for U (20分) 推荐指数:1星

题目

在这里插入图片描述Sample Input:

helloworld!

Sample Output:

h   !
e   d
l   l
lowor

分析

推荐指数:1星
按照指定形状输出数据,也是一个常考的知识点。像U形,回型等。

要点

  • 延边遍历,需要固定住某一遍
  • strlen(s) + 2其实是由题目得出的条件,(因为两个角有重复)
  • 从后遍历,要检查 i–
  • 使用memset来进行 0, 1, ’ '的赋值

题解

#include <iostream>
#include <string.h>
using namespace std;
int main(){
#ifndef ONLINE_JUDGE
    freopen("data.txt", "r", stdin);
#endif // ONLINE_JUDGE
    char c[81], u[30][30];
    memset(u, ' ', sizeof(u)); ///另一种赋值形式
    scanf("%s", c);
    int n = strlen(c) + 2;
    int n1 = n / 3, n2 = n / 3 + n % 3, index = 0; ///这个求出来题就解了
    for(int i = 0; i < n1; i++) u[i][0] = c[index++];
    for(int i = 1; i <= n2 - 2; i++) u[n1-1][i] = c[index++];
    for(int i = n1 - 1; i >= 0; i--) u[i][n2-1] = c[index++];
    for(int i = 0; i < n1; i++) {
        for(int j = 0; j < n2; j++)
            printf("%c", u[i][j]);
        printf("\n");
    }
    return 0;
}

1032 Sharing (25分)

题目

在这里插入图片描述Sample Input 1:

11111 22222 9
67890 i 00002
00010 a 12345
00003 g -1
12345 D 67890
00002 n 00003
22222 B 23456
11111 L 00001
23456 e 67890
00001 o 00010

Sample Output 1:

67890

Sample Input 2:

00001 00002 4
00001 a 10001
10001 s -1
00002 a 10002
10002 t -1

Sample Output 2:

-1

分析

静态数组的题目

要点

  • 使用scanf的时候,在有%c时,必须每一位都对齐输入
  • 使用结构体记录的情况下,可以将visit数组对应为struct中的flag属性
  • 结构体的快速构建: node[a] = {data, b, false}
  • 遍历 数组链表可以用for,也可以用while

题解

#include <cstdio>
using namespace std;
struct NODE {
    char key;
    int next;
    bool flag; ///思考的一样,有个标志判断上一个是否visit过
}node[100000]; ///由题知N<=100000, 故直接使用链接数组即可
int main() {
    int s1, s2, n, a, b;
    scanf("%d%d%d", &s1, &s2, &n);
    char data;
    for(int i = 0; i < n; i++) {
        scanf("%d %c %d", &a, &data, &b);
        node[a] = {data, b, false}; ///结构体的快速赋值
    }
    for(int i = s1; i != -1; i = node[i].next)
        node[i].flag = true;
    for(int i = s2; i != -1; i = node[i].next) {
        if(node[i].flag == true) {
            printf("%05d", i);
            return 0;
        }
    }
    printf("-1");
    return 0;
}

1033 To Fill or Not to Fill (25分)推荐:1星

题目

在这里插入图片描述Sample Input 1:

50 1300 12 8
6.00 1250
7.00 600
7.00 150
7.10 0
7.20 200
7.50 400
7.30 1000
6.85 300

Sample Output 1:

749.17

Sample Input 2:

50 1300 12 2
7.10 0
7.00 600

Sample Output 2:

The maximum travel distance = 1200.00

分析

推荐:1星
这道题有3星的难度,模拟题,难度在于判断条件思路
需要尽量想好各种意外情况
难点,在于条件判断较多,模拟思路很重要。

要点

  • 起点、终点的处理。
  • 过滤掉已经开过的点
  • leftDis : 到站后,还有多少距离可以开,这个变量主要应对:可行驶距离内,没有比当前站更合算的价格,所以当前站要多买,后面看情况选一个
  • 当最小点,且接下来极小点比不过最小点情况时,最小点加满,余下补上极点

题解

///只是穷举
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const int inf = 99999999;
struct station {
    double price, dis;
};
bool cmp1(station a, station b) { ///按距离排序
    return a.dis < b.dis;
}
int main() {
    #ifndef ONLINE_JUDGE
    freopen("data.txt", "r", stdin);
    #endif // ONLINE_JUDGE
    double cmax, d, davg;
    int n;
    scanf("%lf%lf%lf%d", &cmax, &d, &davg, &n);
    vector<station> sta(n + 1);
    sta[0] = {0.0, d}; ///终点站
    for(int i = 1; i <= n; i++)
        scanf("%lf%lf", &sta[i].price, &sta[i].dis);
    sort(sta.begin(), sta.end(), cmp1);
    double nowdis = 0.0, maxdis = 0.0, nowprice = 0.0, totalPrice = 0.0, leftdis = 0.0;
    if(sta[0].dis != 0) { ///第一个油点就到不了——考虑开头, 中途, 结尾3段
        printf("The maximum travel distance = 0.00");
        return 0;
    } else {
        nowprice = sta[0].price; ///当前需要花费的油钱
    }
    while(nowdis < d) {
        maxdis = nowdis + cmax * davg; ///当前能开的最远距离
        double minPriceDis = 0, minPrice = inf; ///遍历所有可到达的点,找到最便宜的可到达点
        int flag = 0;
        for(int i = 1; i <= n && sta[i].dis <= maxdis; i++) { ///由近到远遍历
            if(sta[i].dis <= nowdis) continue; ///已经开过的点
            if(sta[i].price < nowprice) { ///可以去的点
                totalPrice += (sta[i].dis - nowdis - leftdis) * nowprice / davg;
                leftdis = 0.0;
                nowprice = sta[i].price;
                nowdis = sta[i].dis;
                flag = 1;
                break;
            }
            if(sta[i].price < minPrice) {
                minPrice = sta[i].price;
                minPriceDis = sta[i].dis;
            }
        }
        if(flag == 0 && minPrice != inf) {
            totalPrice += (nowprice * (cmax - leftdis / davg));
            leftdis = cmax * davg - (minPriceDis - nowdis);
            nowprice = minPrice;
            nowdis = minPriceDis;
        }
        if(flag == 0 && minPrice == inf) { ///最后到不了的点
            nowdis += cmax * davg;
            printf("The maximum travel distance = %.2f", nowdis);
            return 0;
        }
    }
    printf("%.2f", totalPrice);
    return 0;
}

1034 Head of a Gang (30分) 推荐:1星

题目

在这里插入图片描述Sample Input 1:

8 59
AAA BBB 10
BBB AAA 20
AAA CCC 40
DDD EEE 5
EEE DDD 70
FFF GGG 30
GGG HHH 20
HHH FFF 10

Sample Output 1:

2
AAA 3
GGG 3

Sample Input 2:

8 70
AAA BBB 10
BBB AAA 20
AAA CCC 40
DDD EEE 5
EEE DDD 70
FFF GGG 30
GGG HHH 20
HHH FFF 10

Sample Output 2:

0

分析

推荐:经典
dfs经典题 : 可直接用作同类型的模板

要点

  • 字符串 和 整型的映射
  • travel中还有一个条件判断
  • dfs中用别名来实现数值的累加

题解

#include <iostream>
#include <map>
using namespace std;
map<string, int> stringToInt;
map<int, string> intToString;
map<string, int> ans; ///人名《——》权重
int idNumber = 1, k;
int stoifunc(string s) {  ///将字符串转换成数字,以便后面做图搜索
    if(stringToInt[s] == 0) { ///如果没有
        stringToInt[s] = idNumber;
        intToString[idNumber] = s;
        return idNumber++;
    } else {
        return stringToInt[s];
    }
}
int G[2010][2010], weight[2010]; ///给的范围要根据题意来
bool vis[2010];
void dfs(int u, int &head, int &numMember, int &totalweight) { ///三个别名
    vis[u] = true; ///已查
    numMember++; ///人数++
    if(weight[u] > weight[head]) ///边界条件的处理
        head = u;
    for(int v = 1; v < idNumber; v++) {
        if(G[u][v] > 0) { ///有路可去
            totalweight += G[u][v];
            G[u][v] = G[v][u] = 0; ///置零-》防止回环
            if(vis[v] == false) ///还未去过的点
                dfs(v, head, numMember, totalweight);
        }
    }
}
void dfsTrave() {
    for(int i = 1; i < idNumber; i++) {
        if(vis[i] == false) { ///开始搜索
            int head = i, numMember = 0, totalweight = 0;
            dfs(i, head, numMember, totalweight);
            if(numMember > 2 && totalweight > k) ///如果人数大于2且过阈值
                ans[intToString[head]] = numMember;
        }
    }
}
int main() {
#ifndef ONLINE_JUDGE
    freopen("data.txt", "r", stdin);
#endif // ONLINE_JUDGE
    int n, w;
    cin >> n >> k;
    string s1, s2;
    for(int i = 0; i < n; i++) {
        cin >> s1 >> s2 >> w;
        int id1 = stoifunc(s1);
        int id2 = stoifunc(s2);
        weight[id1] += w; ///每个点的总权重
        weight[id2] += w;
        G[id1][id2] += w; /// A->B + B->A == A-B
        G[id2][id1] += w;
    }
    dfsTrave();
    cout << ans.size() << endl;
    for(auto it = ans.begin(); it != ans.end(); it++)
        cout << it->first << " " << it->second << endl;
    return 0;
}

1035 Password (20分)

题目

在这里插入图片描述Sample Input 1:

3
Team000002 Rlsp0dfa
Team000003 perfectpwd
Team000001 R1spOdfa

Sample Output 1:

2
Team000002 RLsp%dfa
Team000001 R@spodfa

Sample Input 2:

1
team110 abcdefg332

Sample Output 2:

There is 1 account and no account is modified

Sample Input 3:

2
team110 abcdefg222
team220 abcdefg333

Sample Output 3:

There are 2 accounts and no account is modified

题解

//需要仔细审题
#include <string>
#include <iostream>
#include <vector>
using namespace std;
int main() {
#ifndef ONLINE_JUDGE
	freopen("data.txt", "r", stdin);
#endif
	int n;
	scanf("%d", &n);
	vector<string> v;
	for (int i = 0; i < n; ++i) {
		string name, password;
		cin >> name >> password;
		int len = password.size(), flag = 0;
		for (int j = 0; j < len; ++j) {
			switch (password[j]) {
			case '1': password[j] = '@' ; flag = 1; break;
			case '0': password[j] = '%'; flag = 1; break;
			case 'l': password[j] = 'L'; flag = 1; break;
			case 'O': password[j] = 'o'; flag = 1; break;
			}
		}
		if (flag) {
			string tmp = name + " " + password;
			v.push_back(tmp);
		}
	}
	int cnt = v.size();
	if (cnt != 0) {
		printf("%d\n", cnt);
		for (int i = 0; i < cnt; ++i) {
			cout << v[i] << endl;
		}
	}
	else if (n == 1) {
		printf("There is 1 account and no account is modified");
	}
	else {
		printf("There are %d accounts and no account is modified", n); //这些应该直接从题干复制过来
	}
	return 0;
}

1036 Boys vs Girls (25分)

题目

在这里插入图片描述Sample Input 1:

3
Joe M Math990112 89
Mike M CS991301 100
Mary F EE990830 95

Sample Output 1:

Mary EE990830
Joe Math990112
6

Sample Input 2:

1
Jean M AA980920 60

Sample Output 2:

Absent
Jean AA980920
NA

分析

寻找最值的题通常只需要一个变量来记录即可。
不同最值则设不同变量。

题解

///遍历数组,找最大最小值,并记录
#include <string>
#include <iostream>

using namespace std;

int main() {
#ifndef ONLINE_JUDGE
	freopen("data.txt", "r", stdin);
#endif
	int n;
	scanf("%d", &n);
	string female, male;
	int femalescore = -1, malescore = 101;
	for (int i = 0; i < n; ++i) {
		string name, sex, id;
		cin >> name >> sex >> id;
		int score;
		scanf("%d", &score);
		if (sex == "F") {
			if (femalescore < score) {
				femalescore = score;
				female = name + " " + id;
			}
		}
		else {
			if (malescore > score) {
				malescore = score;
				male = name + " " + id;
			}
		}
	}

	if (femalescore != -1) {
		cout << female << endl;
	}
	else {
		printf("Absent\n");
	}

	if (malescore != 101) {
		cout << male << endl;
	}
	else {
		printf("Absent\n");
	}

	if (femalescore != -1 && malescore != 101) {
		printf("%d", femalescore - malescore);
	}
	else {
		printf("NA");
	}
	return 0;
}

1037 Magic Coupon (25分)

题目

在这里插入图片描述
Sample Input:

4
1 2 4 -1
4
7 6 -2 -3

Sample Output:

43

分析

思路,把 最小负号的相乘 + 最大正数相乘 = 结果值

题解

#include <algorithm>
#include <iostream>
using namespace std;

long long a[100010], b[100010], sum = 0;
int main() {
	int x, y;
	scanf("%d", &x);
	for (int i = 0; i<x; i++) scanf("%lld", &a[i]);
	scanf("%d", &y);
	for (int i = 0; i<y; i++) scanf("%lld", &b[i]);
	sort(a, a + x);  ///从小到达排序
	sort(b, b + y);
	int j = 0, k = 0;
	while (a[j]<0 && b[k]<0) {  //这里不用过多限定,因为输入本身就有一定的限定
		sum += a[j] * b[k];
		j++; k++;
	}
	j = x - 1; k = y - 1;
	while (a[j]>0 && b[k]>0) {
		sum += a[j] * b[k];
		j--; k--;
	}
	printf("%lld", sum);
	return 0;
}

1038 Recover the Smallest Number (30分) 推荐:2星

题目

在这里插入图片描述Sample Input:

5 32 321 3214 0229 87

Sample Output:

22932132143287

分析

推荐:2星
没思路的话,也可以直接穷举,至少能得一些分。

要点

  • 直接拼接字符串 a 和 b 即可

题解

#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
bool cmp0(string a, string b) {
    return a + b < b + a; ///比较两个的拼接, 既然两个不等,拼接上就可以啦
}
string str[10010];
int main() {
#ifndef ONLINE_JUDGE
    freopen("data.txt", "r", stdin);
#endif // ONLINE_JUDGE
    int n;
    scanf("%d", &n);
    for(int i = 0; i < n; i++)
        cin >> str[i];
    sort(str, str + n, cmp0);
    string s;
    for(int i = 0; i < n; i++) ///结果拼凑
        s += str[i];
    while(s.length() != 0 && s[0] == '0') ///过滤队首的0
        s.erase(s.begin());
    if(s.length() == 0) cout << 0; ///特判
    cout << s;
    return 0;
}

1039 Course List for Student (25分)

题目

在这里插入图片描述Sample Input:

11 5
4 7
BOB5 DON2 FRA8 JAY9 KAT3 LOR6 ZOE1
1 4
ANN0 BOB5 JAY9 LOR6
2 7
ANN0 BOB5 FRA8 JAY9 JOE4 KAT3 LOR6
3 1
BOB5
5 9
AMY7 ANN0 BOB5 DON2 FRA8 JAY9 KAT3 LOR6 ZOE1
ZOE1 ANN0 BOB5 JOE4 JAY9 FRA8 DON2 AMY7 KAT3 LOR6 NON9

Sample Output:

ZOE1 2 4 5
ANN0 3 1 2 5
BOB5 5 1 2 3 4 5
JOE4 1 2
JAY9 4 1 2 4 5
FRA8 3 2 4 5
DON2 2 4 5
AMY7 1 5
KAT3 3 2 4 5
LOR6 4 1 2 4 5
NON9 0

分析

使用散列可以大大提高查询的速度,但更占内存, getID是关键,只适用于3~5个字符
使用map和set可以更加快速的实现。其实也差不多啦
各有优劣,视情况使用

题解

本题用的散列,查表,我的话可能会用map来记录每个学生

#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
int getid(char *name) { ///散列,学生名称由4个字符构成
    int id = 0;
    for(int i = 0; i < 3; i++) ///3个Letter
        id = 26 * id + (name[i] - 'A');
    id = id * 10 + (name[3] - '0'); ///1个数字
    return id;
}
const int maxn = 26 * 26 * 26 * 10 + 10; ///最大
vector<int> v[maxn]; ///直接开向量数组

int main() {
#ifndef ONLINE_JUDGE
    freopen("data.txt", "r", stdin);
#endif // ONLINE_JUDGE
    int n, k, no, num, id = 0;
    char name[5];
    scanf("%d %d", &n, &k);
    for(int i = 0; i < k; i++) {
        scanf("%d %d", &no, &num);
        for(int j = 0; j < num; j++) {
            scanf("%s", name);
            id = getid(name);
            v[id].push_back(no);
        }
    }
    for(int i = 0; i < n; i++) {
        scanf("%s", name);
        id = getid(name);
        sort(v[id].begin(), v[id].end());
        printf("%s %lu", name, v[id].size()); /// .size()返回unsighed int, 用d也可以,不行就用lu
        for(int j = 0; j < v[id].size(); j++)
            printf(" %d", v[id][j]);
        printf("\n");
    }
    return 0;
}

1040 Longest Symmetric String (25分) 推荐:两星

题目

在这里插入图片描述Sample Input:

Is PAT&TAP symmetric?

Sample Output:

11

分析

推荐:两星
最长回文字符串:
1.动态规划 :dp数组是关键,理解成每一个维都一个字符串, 然后是匹配长度
dp[i][j]的意思, 从i到j都相等
2.马拉车算法(化奇偶为奇)
要点:插入#,开头入$, 求p数组, 从左往右,j点作为曾经的点已经算过
j = 2*id - i , j 是 i 关于id的对称点
3.暴力解法(中间扩展):可以用来获取一部分分数,可以全对,判断奇偶关系即可
4.扩张KMP算法
注意:出错第一遍,先检查ONLINE_JUDGE

要点

动态规划:字符串匹配的关键在于如何利用已经计算过得部分

题解

动态规划

#include <iostream>
using namespace std;
int dp[1010][1010];
int main() {
    #ifndef ONLINE_JUDGE
    freopen("data.txt", "r", stdin);
    #endif // ONLINE_JUDGE
    string s;
    getline(cin, s);
    int len = s.length(), ans = 1;
    ///i与i,i与i-1相比较, 所有长度为2的相同已匹配完
    for(int i = 0; i < len; i++) {  ///找到前后一样的字母
        dp[i][i] = 1;
        ///解决偶数的数据
        if(i < len - 1 && s[i] == s[i+1]) {
            dp[i][i+1] = 1;
            ans = 2;
        }
    }
    ///算法复杂度近似 nlogn
    ///L==3 , i = 0时, j = 2, i+1 = 1 , j - 1 = 1, 即中心位置
    for(int L = 3; L <= len; L++) { ///从3开始找, 状态转移方程
        for(int i = 0; i + L - 1 < len; i++) {
            int j = i + L -1;
            ///L==3 , i = 0时, j = 2, i+1 = 1 , j - 1 = 1, 即中心位置,状态转移
            if(s[i] == s[j] && dp[i+1][j-1] == 1) {
                dp[i][j] = 1;
                ans = L;
            }
        }
    }
    printf("%d", ans);
    return 0;
}

暴力解法

#include <iostream>
using namespace std;
int main(){
#ifndef ONLINE_JUDGE
    freopen("data.txt", "r", stdin);
#endif // ONLINE_JUDGE
    string s;
    int maxLength = 0;
    getline(cin, s);
    for(int i = 0; i < s.length(); i++){
        int j = 1;
        while(i - j > 0 && i+j < s.length() && s[i-j] == s[j+i])
            j++;
        if (maxLength < j*2-1)
            maxLength = j * 2 -1;
        j = i+1;
        int t = i;
        while(t>=0 && j<s.length() && s[t] == s[j]){
            t--;j++;
        }
        if (maxLength < j-t-1)
            maxLength = j-t-1;
    }
    printf("%d", maxLength);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值