PTA L2 - (持续更新,小白加上自己的粗略见解)

PTA L2 - 紧急救援

此题的代码是加上自己的理解,有不对的地方求大佬指点

原文链接:https://blog.csdn.net/qq_51668179/article/details/124211465

#include <bits/stdc++.h>
#define PII pair<int, int>
#define inf 0x3f3f3f3f
using namespace std;
const int N=510;
int city[N];//城市
int dis[N];//边权值
int pre[N];//记录和更新所经过的点
int road[N];//所经过的城市数量
int peo[N];//最多人数的数量 
vector<PII> edge[N];
signed main()
{
	int n,m,s,d;
	cin>>n>>m>>s>>d;
	for(int i=0;i<n;i++)
	{
		cin>>city[i];
		peo[i]=city[i];
	}
	for(int i=0;i<m;i++)
	{
		int x,y,l;
		//建双向边边跟权值 
		cin>>x>>y>>l;
		edge[x].push_back(PII(y,l));
		edge[y].push_back(PII(x,l));
	}
	
	memset(pre,-1,sizeof pre);
	memset(dis,inf,sizeof dis);
	priority_queue<PII, vector<PII>, greater<PII> > q;
	//优先队列,按照q.first先排 
	q.push(PII(0,s));
	dis[s]=0;
	road[s]=1;
	while(q.size())
	{
		PII t=q.top();q.pop();
		int dist=t.first;//距离(边的权值) 
		int cur=t.second;//起点 
		if(dis[cur]<dist) continue;
		//我猜dis[cur](应该是其它点到cur的权值,我们称为拐弯到达点)跟直达点的权值相比较
		//若直达点的权值更大那就没有比下去的必要
		for(PII t1 : edge[cur])
		{
			int next=t1.first;//下一个点 
			int len=t1.second;//cur的点到next的距离(权值) 
			if(dis[next]>dis[cur]+len)//若发现其他权值更小则更新 
			{
				dis[next]=dis[cur]+len;
				road[next]=road[cur];
				pre[next]=cur;
				peo[next]=peo[cur]+city[next];
				q.push({dis[next],next});
			} 
			else if(dis[next]==dis[cur]+len)//相等的话当然还要看谁的人数更多啦 
			{
				if(peo[next]<peo[cur] + city[next])
				{
					pre[next] = cur;
                    peo[next] =peo[cur] + city[next];
				}
				road[next]+=road[cur];//但我有点不理解这个路径数在这相加,求大佬指导 
				
			}
		 } 	
	}
	
	cout<<road[d]<<" "<<peo[d]<<endl;
	vector<int> ans;
	while(true)
	{
		ans.push_back(d);//因为per没存储终点d 
		d=pre[d]; 
		if(d==-1) break;
	}
	reverse(ans.begin(),ans.end());
	for(int i=0;i<ans.size();i++)
	{
		if(i==0) cout<<ans[i];
		else cout<<" "<<ans[i];
	 } 
	 return 0;
 } 

 L2-002 链表去重

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int key[N];//键值
int Next[N];//下一地址 
int list1[N];//已经去重的地址 
int list2[N];//被删除的地址 
bool check[N];
signed main()
{
	int start,n;
	cin>>start>>n;
	while(n--)
	{
	   int a,m,b;
	   cin>>a>>m>>b;
	   key[a]=m;
	   Next[a]=b;	
	}
	int k1=0,k2=0;
	for(int i=start;i!=-1;i=Next[i])
	{
		if(!check[abs(key[i])])
		{
			check[abs(key[i])]=true;
			list1[k1++]=i;
		}
		else 
		{
			list2[k2++]=i;
		}
	}
	for(int i=0;i<k1;i++)
	{
		if(i<k1-1) printf("%05d %d %05d\n",list1[i],key[list1[i]],list1[i+1]);
		else printf("%05d %d -1\n",list1[i],key[list1[i]]);//最后一个地址肯定是-1啦 
	}
	for(int i=0;i<k2;i++)
	{
		if(i<k2-1) printf("%05d %d %05d\n",list2[i],key[list2[i]],list2[i+1]);
		else printf("%05d %d -1\n",list2[i],key[list2[i]]);//最后一个地址肯定也是-1啦 
	}
 } 

 L2-003 月饼  

我的代码:少一个样例没过,不知道为什么

#include <bits/stdc++.h>
using namespace std;
const int N=1e3+10;
double w[N],v[N];//w表示库存,v总售价
set<pair<double, double>> mp;
double xx[N];
double yy[N];//xx记录单价,yy记录库存
double sum=0;
signed main()
{
  int n;
  double m;
  cin>>n>>m;
  for(int i=0;i<n;i++) cin>>w[i];
  for(int i=0;i<n;i++) cin>>v[i];
  for(int i=0;i<n;i++)
  {
  	mp.insert({v[i]/w[i],w[i]});
  }
   set<pair<double, double>>::iterator it;
   int k=0;
   for(it=mp.begin();it!=mp.end();it++)//因为set是自动升序,要改为降序所以我们要记录一下
   {
       xx[k]=it->first;
       yy[k]=it->second;
       k++;
   }
  for(int i=k-1;i>=0;i--)
  {
    double x=xx[i];
    double y=yy[i]; 
   	if(m-y<=0) 
   	{
   	  sum+=x*m;
   	  break;
	}
	sum+=x*y;
    m=m-y;
  }
  printf("%.2lf",sum);
 } 

正确代码:

#include<iostream>
#include<algorithm>
using namespace std;
typedef struct {
	double t;//库存
	double p;//单价
}moon;
bool cmp(moon m1,moon m2){
	return m1.p>m2.p;//降序排列
}
int main(void) {
	int n, T;
	cin >> n >> T;
	moon *m = new moon[n];
	for (int i = 0; i < n; i++) 
		cin >> m[i].t;
	for (int i = 0; i < n; i++) {
		cin >> m[i].p;
		m[i].p /= m[i].t;//算单价
	}
	double sum = 0;
	sort(m, m + n,cmp);
	for (int i = 0; i <n; i++) {
		if (T - m[i].t <= 0) {
			sum += m[i].p*T;
			break;
		}
		T = T - m[i].t;
		sum += m[i].p*m[i].t;
	}
    printf("%.2lf",sum);
}

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

原文链接:L2-004 这是二叉搜索树吗?(二叉树)_l2-004 这是二叉搜索树吗?-CSDN博客

但我发现一个有趣的点:

输出的那里,这样居然是错的,

 for(int i=0;i<n;i++)
      {
          cout<<a[i];
          if(i!=n-1) cout<<" ";
      }

这样是对的,但是用特殊字符测试过,它们没有区别呀;

printf("YES\n%d",ans[0]);
        for(int i = 1;i < n;i++) printf(" %d",ans[i]);

#include<bits/stdc++.h>
using namespace std;
const int N = 1e3+10;
int a[N],n;

vector<int> ans;

void dfs1(int root,int tail){
	if(root > tail) return;
	int l = root + 1,r = tail;
	while(a[l] < a[root] && l <= tail) l++;
	while(a[r] >= a[root] && r > root) r--;
	if(l - r != 1) return;//因为要刚好越过分界线
	dfs1(root+1,r);//向左子树递归
	dfs1(l,tail);//向右子树递归
	ans.push_back(a[root]);//将当前的父节点放入答案
	//如果我们发现是一个二叉搜索树那么ans存的就是后根遍历的结果,
	//因为是递归左右子树后才放入ans中的,下面同理
}

void dfs2(int root,int tail){
	if(root > tail) return;
	int l = root + 1,r = tail;
	while(a[l] >= a[root] && l <= tail) l++;
	while(a[r] < a[root] && r > root) r--;
	if(l - r != 1) return;
	dfs2(root+1,r);
	dfs2(l,tail);
	ans.push_back(a[root]);
}

int main()
{
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	cin>>n;
	for(int i = 0;i < n; ++i) cin>>a[i];
	
	dfs1(0,n-1);
	if(ans.size() != n){
		ans.clear();
		dfs2(0,n-1);
	}
	if(ans.size() == n) {
	 printf("YES\n%d",ans[0]);
        for(int i = 1;i < n;i++) printf(" %d",ans[i]);

	} else {
		cout<<"NO"<<endl;
	}

	return 0;
}

L2-005 集合相似度

这题我辗转反侧了好久,我哭了,没看好题目

我的代码,还是有一个样例没过:

#include <bits/stdc++.h>
using namespace std;
const int N=1e4+10;
int cnt1[N];
int g[N][N];
signed main()
{
    cin.tie(0);
    cout.tie(0);
	int n,m;
	scanf("%d",&n);
	int count=1;
	while(n--)
	{
		int t1;
		scanf("%d",&t1);
		cnt1[count]=t1;//编号从一开始的元素数量
		for(int i=1;i<=t1;i++)
		{
		   cin>>g[count][i];//存储元素
		}	
		count++;
	}
	scanf("%d",&m);
	while(m--)
	{
		int x,y;
		cin>>x>>y;
        set<int> tt1;//所有不同元素
        set<int> tt2;//编号为x的不同元素
        int cc=0;
		for(int j=1;j<=cnt1[x];j++) tt1.insert(g[x][j]);
        for(int j=1;j<=cnt1[y];j++) tt1.insert(g[y][j]);
        for(int j=1;j<=cnt1[x];j++) tt2.insert(g[x][j]);
        set<int>::iterator it;
        for(it=tt2.begin();it!=tt2.end();it++)//有一个样例超时了,o(n*n)可能这里要优化一下
        {
            for(int j=1;j<=cnt1[y];j++)
            {
                 if(*it==g[y][j]) 
                 {
                     cc++;//相同元素数量
                     break;
                 }
            }
        }
		
		double ans=((double)cc)/((double)tt1.size());
		ans=ans*100;
		printf("%.2lf%\n",ans);
		
	}
}

正确代码:

#include <bits/stdc++.h>
using namespace std;
const int N=100;
signed main()
{
  cin.tie(0);
  cout.tie(0);
 int n,k;
 cin>>n;
 vector<set<int>>v(N);
 for(int i=1;i<=n;i++)
 {
   int m;
   cin>>m;
   set<int> st;
   while(m--)
   {
     int num;
	 cin>>num;
	 st.insert(num);
   }
   	v[i]=st;
 }
 
 cin>>k;
 while(k--)
 {
 	int a,b;
 	cin>>a>>b;
 	int common=0;
 	set<int>::iterator it;
 	for(it=v[a].begin();it!=v[a].end();it++)
 	{
 		if(v[b].count(*it))
 		{
 			common++;
		 }
	 }
	 printf("%.2lf%%\n",common*100.0/(v[a].size()+v[b].size()-common));
 }
 
 } 

L2-008 最长对称子串

#include <bits/stdc++.h>
using namespace std;
signed main()
{
    string s;
    getline(cin,s);
    string s1;
	for(int i=0;i<s.size();i++)
	{
	  s1+="#";
	  s1+=s[i];
	} 
	s1+="#";
	int mx=0;
    for(int i=0;i<s1.size();i++)
    {
    	int l=i-1,r=i+1;
    	int cnt=1;
    	while(s1[l]==s1[r]&&l>=0&&r<s1.size()) 
    	{
    		cnt+=2;
    		r++;
    		l--;
		}
    	if(s1[l+1]=='#')cnt=cnt/2;
    	else cnt=cnt/2+1;
    	mx=max(mx,cnt);
	}
	cout<<mx;
}

L2-009 抢红包

#include <bits/stdc++.h>
using namespace std;
const int N=1e4+10;
struct Hongbao  
{
	int id;//编号
	int num=0;//数量
	double sal=0;//收入金额
	
};
bool cmp(Hongbao ss1,Hongbao ss2)//排序
{
	if(ss1.sal==ss2.sal)
	{
		if(ss1.num==ss2.num)
		{
			return ss1.id<ss2.id;
		}
		return ss1.num>ss2.num;
	}
	return ss1.sal>ss2.sal;
}
signed main()
{
    int n;
    cin>>n;
    Hongbao hongbao[N];
    for(int i=1;i<=n;i++)
    {
    	int k;
    	cin>>k;
    	int sum=0;
    	while(k--)
    	{
    		int x;
			double y;
    		cin>>x>>y;
    		hongbao[x].sal+=y;//所抢到的红包
    		hongbao[x].num+=1;
    		sum+=y;
		}
		hongbao[i].id=i;
		hongbao[i].sal-=sum;//发出去的钱
	}
	sort(hongbao+1,hongbao+n+1,cmp);
	for(int i=1;i<=n;i++)
	{
	    printf("%d %.2lf\n",hongbao[i].id,hongbao[i].sal/100);	
	}
}

l2-010 排座位

我的代码:第二个样例没过,我猜是漏朋友的朋友关系哪里,没注意,哈哈哈所以这题写的时候没用并查集;

#include <bits/stdc++.h>
using namespace std;
const int N=110;
int g[N][N];
signed main()
{
   int n,m,k;
   cin>>n>>m>>k;
   while(m--)
   {
   	int x,y,st;
   	cin>>x>>y>>st;
   	g[x][y]=st;//建立双向边
   	g[y][x]=st;
   }
   while(k--)
   {
   	int x,y;
   	cin>>x>>y;
   	int t1=0;
   	for(int i=1;i<=n;i++)
   	{
   	  if(g[x][i]==1&&g[y][i]==1)//判断是否有共同朋友
   	  {
   	      t1=1;
		  break;	
	  }
	}
   	if(g[x][y]==1) cout<<"No problem"<<endl;//是朋友
   	else if(g[x][y]==-1)//是敌人
   	{
   	   if(t1) cout<<"OK but..."<<endl;//有共同朋友的敌人
	   else cout<<"No way"<<endl;	
	}
   	else cout<<"OK"<<endl;
   }
}

正确代码:

#include<bits/stdc++.h>
using namespace std;
const int N = 1e2+10;
int p[N],n,m,k;
bool enmy[N][N];
int find(int x){
	return x==p[x]?x:find(p[x]);
}

int main()
{
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	cin>>n>>m>>k;
	for(int i = 1;i <= n; ++i) p[i] = i;
	int u,v,w;
	for(int i = 1;i <= m; ++i) {
		cin>>u>>v>>w;
		if(w + 1) {
			u = find(u);//查询根节点 
			v = find(v);
			p[v] = u;//两集合链接,以v点坐标的根节点为u的父亲节点 
		} else {
			enmy[u][v] = enmy[v][u] = true;
		}
	}
	for(int i = 1;i <= k; ++i) {
		cin>>u>>v;
		if(enmy[u][v]) {
			if(find(u) == find(v)) cout<<"OK but..."<<endl;
			else cout<<"No way"<<endl;
		} else {
			if(find(u) == find(v))
				cout<<"No problem"<<endl;
			else  cout<<"OK"<<endl;
		}
	}
	return 0;
}

2020天梯赛 L2-4 网红点打卡攻略(巨坑,哈密顿回路问题)

我的代码:

include <bits/stdc++.h>
using namespace std;
const int N=500;
int g[N][N];
int count1[N];
int cnt;//符合个数
int ans=0x3f3f3f3f;//最便宜价格
int  tt;//最便宜价格序号 
int main() {
	int n,m;
	cin>>m>>n;
	memset(g,-1,sizeof(g));	
	for(int i=1;i<=n;i++)
	{
		int st,ed,w;
		cin>>st>>ed>>w;
		g[st][ed]=w;
		g[ed][st]=w;
	}
	int k;
	cin>>k;
	for(int i=1;i<=k;i++)
	{
		memset(count1,0,sizeof count1);
		int nk;
		cin>>nk;
		bool flag=false;
		int s[nk+5];
		memset(s,0,sizeof s);
		for(int j=1;j<=nk;j++)
		{
			cin>>s[j];
			count1[s[j]]++;
		}
		for(int j1=1;j1<=m;j1++) 
		{
			if(count1[j1]!=1) flag=true;
		}
		if(flag==true) continue;
		s[0]=s[nk+1]=0;
		int sum=0; 
		for(int j=0;j<=nk;j++)
		{
			if(g[s[j]][s[j+1]]<0) flag=true;//注意还有回家的路线 
		    sum+=g[s[j]][s[j+1]];
		 } 
		if(flag==true) continue;
		cnt++;
		if(sum<ans)
		{
			ans=sum;
			tt=i;
		}
		
	}
	cout<<cnt<<endl;
	cout<<tt<<" "<<ans<<endl;

}

正确代码:

#include<bits/stdc++.h>
#define N 202
using namespace std;
int n,m,k,nk;
int g[N][N];
int V[N];
int Count[N];
int cnt,t,ans=0x3f3f3f3f;

int main() {
	memset(g,-1,sizeof(g));	
	cin >> n >> m;
	for(int i=0; i<m; ++i) {
		int u,v,w;
		cin >> u >> v >> w;
		g[u][v] = w;
		g[v][u] = w;
	}
	cin >> k;
	for(int i=1; i<=k; ++i) { //方便输出编号 
		memset(Count,0,sizeof(Count));//每个点只能输出一次 
		cin >> nk;
		bool flag = false;
		vector<int>s(nk+2); 
		for(int j=1; j<=nk; ++j) {
			cin >> s[j];
			Count[s[j]]++;
			if(Count[s[j]]>1) {
				flag = true;  //不能写break,它还没输入完成 
			}
		}
		for(int j1=1; j1<=n; ++j1){
			if(Count[j1]!=1)
			flag = true;  //包含所有点,且每个点只经过一次 
		}
		if(flag == true)continue;//进行下一个案例 
		s[0] = s[nk+1] = 0;//这么处理避免很多特判问题 
		int sum=0;
		for(int j=0; j<=nk; ++j) {
			if(g[s[j]][s[j+1]]<0) {
				flag = true;
				break;
			} 
			sum += g[s[j]][s[j+1]];
		}
		if(flag == true) continue;
		cnt++;
		if(sum<ans&&flag == false) { // flag == false表示它是一个合法的方案 
			ans = sum;
			t = i;//记录第一个合法的下标 
		}
	}
	cout << cnt << endl;
	cout << t << " " << ans << endl;
	return 0;
}

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值