(PTA自主训练4)7-15 球队“食物链”
思路:记录每个点可以到哪些点,简单dfs,存一下遍历顺序,求最小的;
注意:注意剪枝,以及遍历顺序我是用vector来存的,当(未走过的点)不能够走向起点时,剪枝;
代码:
#include<bits/stdc++.h>
using namespace std;
vector< int >q[25];
int vis[25];
int dis[25][25];
vector< int >ans;
int n;
void dfs(int t,vector<int>&path){
if(ans<path)return;
if(path.size()==n){
if(dis[path[n-1]][path[0]]==1){
ans=min(ans,path);
}
return;
}
vis[t] = 1;
int st=0;
for (int i = 1; i <=n ; ++i) {
if(!vis[i]&&dis[i][path[0]])
st=1;
}
if(!st)return;
for (int i = 0; i < q[t].size(); ++i) {
auto g = q[t][i];
if (!vis[g]) {
path.push_back(g);
vis[g]=1;
dfs(g, path);
vis[g]=0;
path.pop_back();
}
}
}
int main(){
cin>>n;
for (int i = 0; i <n ; ++i) {
ans.push_back(29);
}
for(int i=1;i<=n;i++){
string s;
cin>>s;
for(int j=0;j<s.size();j++){
if(s[j]=='W'){
q[i].push_back(j+1);
dis[i][j+1]=1;
}
else if(s[j]=='L'){
q[j+1].push_back(i);
dis[j+1][i]=1;
}
}
}
for(int i=1;i<=n;i++){
vector< int >v;
v.push_back(i);
::memset(vis,0,sizeof vis);
vis[i]=1;
dfs(i,v);
}
if(ans[0]==29){
cout<<"No Solution";
return 0;
}
for (int i = 0; i <n ; ++i) {
cout<<ans[i];
if(i!=n-1)
cout<<' ';
}
}
(PTA自主训练4)7-12 功夫传人
思路: 又是一道搜索题,赛时bfs拿了24分,赛后发现dfs就过了,很奇怪为啥,精度可能有问题
代码1BFS:
#include<bits/stdc++.h>
using namespace std;
vector< int >q[100005];
double ans[100005];
int vis[100005];
int n;
int b[100005];
double z,r;
int main(){
cin>>n>>z>>r;
for(int i=0;i<n;i++){
int k;
cin>>k;
if(k){
while(k--){
int x;
cin>>x;
q[i].push_back(x);
}
}
else{
int x;
cin>>x;
b[i]=x;
vis[i]=1;
}
}
queue< int >qe;
qe.push(0);
ans[0]=z;
while (!qe.empty()){
auto t=qe.front();
qe.pop();
for (auto i:q[t]) {
if (vis[i]) {
ans[i] = ans[t]*(1-r*1.0/100)*b[i];
} else {
ans[i] = ans[t]*(1-r*1.0/100);
qe.push(i);
}
}
}
double res=0;
for (int i = 0; i <n ; ++i) {
if(vis[i])res+=ans[i];
}
cout<<(int )res;
}
代码2:DFS
#include<bits/stdc++.h>
using namespace std;
vector< int >q[100005];
double ans[100005];
int vis[100005];
int n;
double res;
int pd[100005];
int b[100005];
double z,r;
void dfs(int t,double pw){
if(vis[t]){
res+=pw*b[t];
return;
}
for (int i = 0; i <q[t].size() ; ++i) {
dfs(q[t][i],pw*(1-r/100));
}
}
int main(){
cin>>n>>z>>r;
for(int i=0;i<n;i++){
int k;
cin>>k;
if(k){
while(k--){
int x;
cin>>x;
q[i].push_back(x);
pd[x]=1;
}
}
else{
int x;
cin>>x;
b[i]=x;
vis[i]=1;
}
}
dfs(0,z);
cout<<(int )res;
}
(PTA自主训练3)7-10 列车调度
思路:讲真的,赛时没想到咋做,简单的交了一个很nc的代码,赛后补题发现规律性很强,思维题吧,(弱鸡思维跟不上),首先我们是保证得到一个降序的顺序,升序的那个加入ans,下一个数字从ans中找,找不到则加入,找的到则覆盖掉那个找到的位置的数。
考虑到查找以及有序性,提高时间效率则用到二分,因为set即有二分以及定点删除的作用,则使用set,upper_bond;
代码:
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
cin>>n;
vector<int >q;
for(int i=0;i<n;i++){
int x;
cin>>x;
q.push_back(x);
}
vector< int >ans;
ans.push_back(q[0]);
for(int i=1;i<n;i++){
int k=1;
sort(ans.begin(),ans.end());
for(int j=0;j<ans.size();j++){
if(ans[j]>=num[i]){
ans[j]=num[i];
k=0;
break;
}
}
if(k){
ans.push_back(num[i]);
}
}
cout<<ans.size();
}
(PTA自主训练3)7-9 红色警报
思路:
主要是判断连通性:dfs查询连通性,删这个点之前的联通块的数量与删后的对比
代码:
#include<bits/stdc++.h>
using namespace std;
vector<int >ve[505];
int st[505];
int vis[505];
int del[505];
void dfs(int x){
for (int i = 0; i <ve[x].size() ; ++i) {
auto g=ve[x][i];
if(vis[g]==0&&del[g]==0){
vis[g]=1;
dfs(g);
}
}
}
int main(){
int n,m;
cin>>n>>m;
while(m--){
int x,y;
cin>>x>>y;
ve[x].push_back(y);
ve[y].push_back(x);
}
int ans=0;
for (int i = 0; i <n ; ++i) {
if(!vis[i]){
vis[i]=1;
ans++;
dfs(i);
}
}
int k;
cin>>k;
for(int i=0;i<k;i++) {
int x;
cin>>x;
del[x]=1;
::memset(vis,0,sizeof vis);
int ansing=0;
for (int j = 0; j <n ; ++j) {
if(vis[j]==0&&del[j]==0){
vis[j]=1;
ansing ++;
dfs(j);
}
}
if(ans<ansing){
printf("Red Alert: City %d is lost!\n", x);
}
else{
printf("City %d is lost.\n", x);
}
ans=ansing;
}
if(k==n) printf("Game Over.\n");
}
(PTA自主训练3)7-13 是否完全二叉搜索树
思路:根据树的性质,先建树,因为左子树大,右子树小,则可以还原树,然后bfs利用队列找出层序遍历,注意判断不存在的条件
条件:
- 左边不存在,右节点存在
- 根不存在,但左右节点存在
- 左右节点若是有一个不存在,则标记一下
代码:
#include<bits/stdc++.h> using namespace std; const int N=1e4+10; int l[N],r[N],t[N],idx; int vis[N],flag,st; void build(int pos,int val){ if(!vis[pos]){ t[pos]=val; vis[pos]=1; return; }///如果这个节点没有被建立,先建立 ///插入左子树 if(val>t[pos]){ if(l[pos]){ build(l[pos],val); } else{ l[pos]=++idx,build(l[pos],val); } } ////插入右子树 else{ if(r[pos]){ build(r[pos],val); } else{ r[pos]=++idx,build(r[pos],val); } } } void bfs(int x){ queue<int >q; q.push(x); cout<<t[x]; while(!q.empty()){ int tt=q.front(); if(tt!=x){ cout<<' '<<t[tt]; } q.pop(); if(!l[tt]&&r[tt])flag=false;///左边不存在,右节点存在 if(!st&&(l[tt]||r[tt]))flag=false;//////根不存在,但左右节点存在 if(!l[tt]||!r[tt])st=false;////////左右节点若是有一个不存在,则标记一下 if(l[tt])q.push(l[tt]);///压入层序遍历 if(r[tt])q.push(r[tt]); } } int main(){ int n; cin>>n; idx=1; for (int i = 1; i <=n ; ++i) { int g; cin>>g; build(1,g); } flag=st=1; bfs(1); puts(""); if(flag)cout<<"YES"; else cout<<"NO"; }
(PTA自主训练3)7-14 直捣黄龙
思路:利用map映射字符串,建图,跑一遍堆优化的djstl,求最短路,然后用dfs从起点跑向终点,速度相同取ans.size()最大,其次再取cnt最大
代码:
#include<bits/stdc++.h> using namespace std; int n,k,s,e; string sta,ed; int val[205],dis[205],vis[205]; vector<pair<int,int>>g[205]; #define PII pair<int,int> unordered_map<string ,int >sti; unordered_map<int,string >its; vector<int >ans,now; int ansdis=-1,anscnt=-1,anstimes; void djstl(){ fill(dis+1,dis+1+n,INT_MAX); dis[e]=0; priority_queue<PII,vector<PII>,greater<PII>>q; q.emplace(0,e); while (!q.empty()){ auto [d,u]=q.top(); q.pop(); if(vis[u])continue; vis[u]=1; for(auto [v,w]:g[u]){ if(vis[v])continue; if(dis[v]<=d+w)continue; dis[v]=d+w; q.emplace(dis[v],v); } } } void dfs(int x,int d,int cnt){ if(d+dis[x]>ansdis)return; if(x==e&&d==ansdis){ anstimes++; if(now.size()>ans.size()){ anscnt=cnt,ans=now; } else if(now.size()==ans.size()&&cnt>anscnt){ anscnt=cnt,ans=now; } return; } for(auto [v,w]:g[x]){ if(vis[v])continue; now.push_back(v),vis[v]=1; dfs(v,d+w,cnt+val[v]); now.pop_back();vis[v]=0; } return; } int main(){ cin>>n>>k>>sta>>ed; sti[sta]=1,its[1]=sta; for (int i = 2; i <=n ; ++i) { cin>>its[i]>>val[i],sti[its[i]]=i; } s=sti[sta],e=sti[ed]; while(k--){ int u,v,w; string us,vs; cin>>us>>vs>>w; u=sti[us],v=sti[vs]; g[u].push_back({v,w}); g[v].push_back({u,w}); } djstl(); fill(vis, vis + 1 + n, 0); ansdis=dis[s],vis[s]=1; dfs(s,0,0); cout<<sta; for (auto i:ans) { cout<<"->"<<its[i]; } cout<<"\n"<<anstimes<<' '<<ansdis<<' '<<anscnt<<endl; return 0; }
(PTA自主训练3)7-12 愿天下有情人都是失散多年的兄妹
思路:本题主要是是判断俩人是否在五代以内,可以考虑用图来解决,将每个人的母亲与父亲存入图中,从本身跑dfs对父母进行搜索,将搜到的人标记,如果深度五层以内,搜到了曾经标记过的,则说明两人近亲,no
代码:
#include<bits/stdc++.h> using namespace std; int fa[100005],ma[100005],sex[100005],vis[100005],flag; void dfs(int a,int n){ if(n==0)return ; if(vis[a]==1){ flag=1; return; } vis[a]=1; if(fa[a]!=-1&&fa[a]!=0)dfs(fa[a],n-1); if(ma[a]!=-1&&ma[a]!=0)dfs(ma[a],n-1); } int main(){ int n; cin>>n; for (int i = 0; i <n ; ++i) { int num; cin>>num; char c; cin>>c; if(c=='M'){ sex[num]=0; } else sex[num]=1; int f,m; cin>>f>>m; fa[num]=f,ma[num]=m; sex[f]=0,sex[m]=1; } int k; cin>>k; for (int i = 0; i < k ; ++i) { int a,b; ::memset(vis,0,sizeof vis); cin>>a>>b; if(sex[a]==sex[b]){ cout<<"Never Mind\n"; continue; } flag=0; dfs(a,5); dfs(b,5); if(flag==0) cout<<"Yes\n"; else cout<<"No\n"; } }
(PTA训练赛8)L2-3 完全二叉树的层序遍历
思路:又节点的个数,找出后序遍历的序号,然后通过映射,输出其层序遍历的答案,比如:n=8,那么后序遍历则为:8 4 7 2 3 5 6 1,那么其层序遍历的答案则为a[8],a[4],a[7]------等
代码:
#include<bits/stdc++.h>
using namespace std;
int res[31];
int cnt=1;
int n;
int post[32];
void postorder(int t){
if(t>n)
return ;
postorder(t*2);
postorder(t*2+1);
post[t]=cnt++;
}
int main(){
cin>>n;
vector<int>ans;
vector<pair<int,int>>q;
postorder(1);
ans.push_back(0);
for (int i = 1; i <=n ; ++i) {
int x;
cin>>x;
ans.push_back(x);
}
for (int i = 1; i <=n ; ++i) {
cout<<ans[post[i]]<<" \n"[i==n];
}
}
#