pta补题——25分

L2-001 紧急救援

https://pintia.cn/problem-sets/994805046380707840/exam/problems/type/7?problemSetProblemId=994805073643683840&page=1
这个题目是给你一个图,你要从给定起点前往终点,然后每个点都有一个人数,要求你找到最短路径,同时这个路径遇到的人数最多。让你输出最短路径长,经过的人数,还有走过的路线。

这个是带权最短路+路径数量+路径输出。

我们利用dijkstra邻接矩阵求出最短路,同时当路径长度相同时,依照人数来更新最短路径。最后要掌握如何输出走过的路线的方法:我们设立一个数组,数组记录到达当前点时,经过的前一个点是什么。

下面看代码。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=505;
#define PII pair<int,int>
const int inf=INT_MAX;
int n,m,s,d;
int cost[N];//每个城市的人数。
int ren[N];//走到每个城市最多召集多少人。
bool vis[N];//每个城市有没有被走过。
int dis[N];//每个城市到起点的距离。
int num[N];//到达每个城市的最短路径的条数。
int per[N];//为了储存最短路径的城市编号。
struct xx{
	int id,w;//id是城市编号(从0开始),w是路径长度。
};
vector<vector<xx>>a(N);//邻接表。
void solve(){
	cin>>n>>m>>s>>d;
	for(int i=0;i<n;i++){
		cin>>cost[i];
	}
	for(int i=1;i<=m;i++){
		int u,v,w;
		cin>>u>>v>>w;
		a[u].push_back({v,w});
		a[v].push_back({u,w});
	}
	for(int i=0;i<n;i++){
		vis[i]=0;
		ren[i]=cost[i];
		dis[i]=0x3f;
		num[i]=0;
		per[i]=-1;
	}
	num[s]=1;
	dis[s]=0;
	priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>>q;//优先队列。
	q.push({0,s});//按距离远近进行排序存储。
	while(q.size()){
		auto now=q.top();
		q.pop();
		int km=now.first;
		int id=now.second;
		if(vis[id]) continue;//如果走过了,那么我们就跳过。
		else vis[id]=1;//记录走过。
		for(auto tt:a[id]){
			int nex=tt.id,mm=tt.w;
			if(dis[nex]>dis[id]+mm){//如果距离有了新的最小值。那么我们就更新最小值。
				dis[nex]=km+mm;//最小值改变。
				per[nex]=id;//记录当前遍历到的城市的上一个城市为母城市
				ren[nex]=cost[nex]+ren[id];//召集的总人数增加。
				num[nex]=num[id];//道路条数更新。
				q.push({dis[nex],nex});//插入新的节点。
			}else if(dis[nex]==dis[id]+mm){//如果城市长度一样。
				if(ren[nex]<ren[id]+cost[nex]){//如果人数多于原来的人数。
					per[nex]=id;//我们也要更新。记录当前城市是怎么来的。
					ren[nex]=cost[nex]+ren[id];//更新总人数。
				}
				num[nex]+=num[id];//道路条数增加。和人物数量无关。
			}
		}
	}
	cout<<num[d]<<" "<<ren[d]<<endl;
	int z=d;
	vector<int>ans;
	//存储答案。
	while(z!=-1){
		ans.push_back(z);
		z=per[z];
	}
	for(int i=ans.size()-1;i>=0;i--){
		cout<<ans[i];
		if(i==0){
			cout<<endl;
		}else{
			cout<<" ";
		}
	}
}
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	int t=1;
	//	cin>>t;
	while(t--){
		solve();
	}
	return 0;
}

L2-002 链表去重

https://pintia.cn/problem-sets/994805046380707840/exam/problems/type/7?problemSetProblemId=994805072641245184&page=1

这个题是不按顺序给你一个链表的结构,告诉你每个节点的前驱和后继,还有每个结点的数值。给出你链表起点,链表以 -1 为终点。

要求你对链表按照绝对值去重。即相同绝对值的节点只能存在一个。

输出去重后的链表和按输入顺序排列的被删除链表。

这个题的难点在于链表的连接,当一个节点被删除后,他要和后继的后继继续连接起来,同时被删除的链表也要输入的顺序连接起来,所以改变每个节点的后继是一个很困难的事情。

现在有一个好办法解决。

我们首先在输入的时候就找到链表起始节点,然后从起始节点对链表进行遍历。如果遇到绝对值相同的我们把它存在 C 数组里面,C 即代表删除节点所组成的链表。去重后的链表储存在数组 B 当中。

然后我们对节点按特定方式输出就好了。方式见代码。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=505;
#define PII pair<int,int>
struct xx{
	string dds;
	int key;
	string next;
	int num;
};
bool cmp(xx a,xx b){
	return a.num<b.num;
}
void solve(){
	string ads;
	int n;
	cin>>ads>>n;
	vector<xx>a(n+1);
	map<string,int>nx;
	int zz=0;
	for(int i=1;i<=n;i++){
		cin>>a[i].dds>>a[i].key>>a[i].next;
		a[i].num=i;
		if(a[i].dds==ads){
			zz=i;
		}
		nx[a[i].dds]=i;
	}
	vector<xx>b,c;
	map<int,int>u;
	u[abs(a[zz].key)]++;
	b.push_back(a[zz]);
	while(a[zz].next!="-1"){
		if(u[abs(a[nx[a[zz].next]].key)]==0){
			b.push_back(a[nx[a[zz].next]]);
		}else{
			c.push_back(a[nx[a[zz].next]]);
		}
		u[abs(a[nx[a[zz].next]].key)]++;
		zz=nx[a[zz].next];
	}

	for(int i=0;i<b.size();i++){
		cout<<b[i].dds<<" "<<b[i].key<<" ";
		if(i!=b.size()-1){
			cout<<b[i+1].dds<<endl;
		}else{
			cout<<"-1"<<endl;
			break;
		}
	}
	for(int i=0;i<c.size();i++){
		cout<<c[i].dds<<" "<<c[i].key<<" ";
		if(i!=c.size()-1){
			cout<<c[i+1].dds<<endl;
		}else{
			cout<<"-1"<<endl;
			break;
		}
	}
	
}
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	int t=1;
//	cin>>t;
	while(t--){
		solve();
	}
	return 0;
}

!!!L2-004 这是二叉搜索树吗?

https://pintia.cn/problem-sets/994805046380707840/exam/problems/type/7?problemSetProblemId=994805070971912192&page=1

这个是二叉搜索树的知识。然你判断给出的序列是不是一个二叉搜索树或者其镜像的前序遍历序列,如果是的话就输出它的后序遍历序列。

二叉搜索树的话就是左子树都小于根节点,右子树都大于根节点。镜像就是左子树都大于根节点,右子树都小于根节点。

这个题我不会。我不懂树的知识。

首先我们记录一下给出的前序遍历序列。

对前序遍历序列进行搜索。如果搜索的左边界大于右边界我们就返回。然后因为是前序遍历序列,所以第一个点一定是当前子树的根节点。又因为是搜索树的前序遍历序列,所以如果当前遍历的节点小于根节点,我们就继续向后找。不满足条件时就是左子树遍历完了。对于右子树我们往前遍历,如果当前节点小于根节点我们就往前找。如果两个查找后的边界不相邻,我们就return。因为这样的情况不会出现。代表错误。

之后我们就遍历左右子树,然后利用数组记录根节点,以储存后续遍历序列。

如果当前搜索方式没办法找全序列呢,我们就按镜像方法找。如果左边界对应节点小于根节点。我们向后寻找,如果右节点大于跟节点,我们向前寻找。

如果两个都不是,我们输出 NO。

代码:

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
typedef pair<int, int> PII;
const int inf = LLONG_MAX / 10;
const int mod = 1e9+7;
// #define x first
// #define y second
const int N=1005;
int n;
int a[N],ans[N];
bool is;
int k;
void dfs(int l,int r){
    if(l>r){
        return;
    }
    int i=l+1,j=r;
    if(!is){
        while(i<=r and a[l]>a[i]){
            i++;
        }
        while(j>l and a[l]<=a[j]){
            j--;
        }
    }else{
        while(i<=r and a[l]<=a[i]){
            i++;
        }
        while(j>l and a[l]>a[j]){
            j--;
        }
    }
    if(i-j!=1){
        return;
    }
    dfs(l+1,j);
    dfs(i,r);
    k++;
    ans[k]=a[l];
}
void miaojiachun(){
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    k=0;
    dfs(1,n);
    if(k!=n){
        is=1;
        k=0;
        dfs(1,n);
    }
    if(k==n){
        cout<<"YES"<<endl;
        cout<<ans[1];
        for(int i=2;i<=n;i++){
            cout<<" "<<ans[i];
        }
        cout<<endl;
    }else{
        cout<<"NO"<<endl;
    }
}

signed main(){
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    int ING = 1;
    // cin>>ING;
    // cin.ignore();
    while (ING--) {
        miaojiachun();
    }
    return 0;
}

L2-005 集合相似度

这个题就是利用集合的特定方法。他给我们两个数组,去重后作为集合。让我们求集合交集个数和其他数的比值。

这里用到set_intersection()方法,是找到两个集合的交集。然后复制到新集合中去。

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
// #define ll long long
typedef pair<int, int> PII;
const int N = 55 + 7;
const int inf = LLONG_MAX / 10;
const int mod = 998244353;
// #define x first
// #define y second
set<int>st[N];
void miaojiachun(){
    int n;
    cin>>n;

    for(int i=1;i<=n;i++){
        int k;
        cin>>k;
        for(int j=1;j<=k;j++){
            int x;
            cin>>x;
            st[i].insert(x);
        }
    }
    int q;
    cin>>q;

    while(q--){
        int a,b;
        cin>>a>>b;
        set<int>v;
        set_intersection(st[a].begin(),st[a].end(),st[b].begin(),st[b].end(),inserter(v,v.begin()));
        int nc=(int)v.size();
        int nt=(int)st[a].size()+(int)st[b].size()-nc;
        double res=nc*1.0/nt*100;
        cout<<fixed<<setprecision(2)<<res<<"%"<<endl;
    }
}
signed main() {
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    int ING = 1;
    // cin>>ING;
    // cin.ignore();
    while (ING--) {
        miaojiachun();
    }
    return 0;
}

L2-006 树的遍历

L2-008 最长对称子串

https://pintia.cn/problem-sets/994805046380707840/exam/problems/type/7?page=1&problemSetProblemId=994805067704549376

这个题是给你一个字符串,让你求出他的最长对称字串长度。
这个题目中给出的数据范围很小,我们可以直接二分暴力求解。然后我新学习了马拉车算法。这个就是求一个字串的最长对称字串,我看完之后还是没有学会,我现在决定考前先考背来记忆。
下面给出二分和马拉车算法代码:

点击查看二分代码
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
// #define ll long long
typedef pair<int, int> PII;
const int N = 10005 + 7;
const int inf = LLONG_MAX / 10;
const int mod = 998244353;
int n;
string s;
bool check(int x){
    // cout<<x<<endl;
    for(int i=0;i<n-x+1;i++){
        int l=i,r=i+x-1;
        int k=1;
        while(l<=r){
            if(s[l]!=s[r]){
                k=0;
                break;
            }
            l++;
            r--;
        }
        if(k==1){
            return true;
        }
    }
    return false;
}
void miaojiachun(){
    getline(cin,s);
    n=s.size();
    int l=1,r=s.size();
    int ans=0;
    while(l<=r){
        int mid=(l+r)>>1;
        if(!check(mid) and !check(mid+1)){//这里要注意,因为我们二分有可能判了一个数不对后,直接跳过这个数字加一或跳过这个数字减一,所以我们判断两个情况都不符合是我们再进行操作。
            r=mid-1;
        }else{
            l=mid+1;
            ans=mid;
        }
    }
    cout<<ans<<endl;
}
signed main() {
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	int ING = 1;
	// cin>>ING;
	// cin.ignore();
	while (ING--) {
		miaojiachun();
	}
	return 0;
}
点击查看马拉车代码
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
// #define ll long long
typedef pair<int, int> PII;
const int N = 10005 + 7;
const int inf = LLONG_MAX / 10;
const int mod = 998244353;
int len[N];//代表I为中心的最长回文子串的长度。
string init(string s){
	string res;
	res+="@";
	for(int i=0;i<s.size();i++){
		res+="#";
		res+=s[i];
	}
	res+="#";
	res+="$";
	return res;
}
int Manacher(string s){
	memset(len,0,sizeof len);
	int mx=0,id=0;
	int ans=0;
	for(int i=1;i<s.size()-1;i++){
		if(mx>i){
			len[i]=min(mx-i,len[2*id-i]);
		}else{
			len[i]=1;
		}
		while(s[i-len[i]]==s[i+len[i]]){
			++len[i];
		}
		if(i+len[i]>mx){
			mx=i+len[i];
			id=i;
		}
		ans=max(ans,len[i]);
	}
	return ans-1;
}

void miaojiachun(){
	string s;
	getline(cin,s);
	string temp=init(s);
	cout<<Manacher(temp);
}
signed main() {
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	int ING = 1;
	// cin>>ING;
	// cin.ignore();
	while (ING--) {
		miaojiachun();
	}
	return 0;
}

除此之外还有动态规划代码。我动态规划也是薄弱项。

当回⽂字串为奇数的时候,j 表示 i-j 与 i+j 构成的回⽂字串⻓度;当回⽂字串⻓度为偶数的时候,j 表示 i+1 左边 j 个字符⼀直到 i 右边 j 个字符的回⽂字串⻓度~

⽤maxvalue保存遍历结果得到的最⼤值并且输出~

点击查看动态规划代码
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
// #define ll long long
typedef pair<int, int> PII;
const int N = 10005 + 7;
const int inf = LLONG_MAX / 10;
const int mod = 998244353;

void miaojiachun(){
	//有两种可能,一种是回文字符串长度为奇数,一种是偶数的情况。
	string s;
	getline(cin,s);
	int maxn=0,temp;
	int len=s.size();
	for(int i=0;i<len;i++){
		temp=1;
		for(int j=1;j<len;j++){
			if(i-j<0 or i+j>=len or s[i-j]!=s[i+j]){
				break;
			}
			temp+=2;
		}
		maxn=max(maxn,temp);
		temp=0;
		for(int j=1;j<len;j++){
			if(i-j+1<0 or i+j>=len or s[i-j+1]!=s[i+j]){
				break;
			}
			temp+=2;
		}
		maxn=max(maxn,temp);
	}
	cout<<maxn<<endl;
}
signed main() {
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	int ING = 1;
	// cin>>ING;
	// cin.ignore();
	while (ING--) {
		miaojiachun();
	}
	return 0;
}
posted @ 2025-03-05 20:02  miao-jc  阅读(13)  评论(0)    收藏  举报