PTA L2 - 紧急救援
此题的代码是加上自己的理解,有不对的地方求大佬指点
原文链接:https://blog.youkuaiyun.com/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 这是二叉搜索树吗?-优快云博客
但我发现一个有趣的点:
输出的那里,这样居然是错的,
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;
}