目录
L3-016 二叉搜索树的结构 (30 分)(数组+字符串+函数定义+不用定义树结构的)
L3-001 凑零钱 (30 分)(回溯+剪枝)
【分析】
- dfs搜一下,因为排过序,所以数组递增排列,故第一组满足sum==w的序列一定是满足条件的序列,所以不用把所有的序列都搜出来的;
- 注意剪枝;一次符合之后f=1之后就不再进行递归直接return掉;如果所有的钱加起来都达不到要求,就不用搜了【这里会wa倒数第二个点和T最后一个点】;
【代码】
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e4+10;
int a[maxn];
vector<int>dp,t;
int n,w,sum,f;
void dfs(int x)
{
if(f)return;
if(sum>w || x>=n)return;
if(sum==w)
{
f=1;
t.assign(dp.begin(),dp.end());
return;
}
dp.push_back(a[x]);
sum+=a[x];
dfs(x+1);
sum-=a[x];dp.pop_back();
dfs(x+1);
}
int main()
{
scanf("%d%d",&n,&w);
int sum=0;
for(int i=0;i<n;++i)
{
scanf("%d",&a[i]);
sum+=a[i];
}
sort(a,a+n);
if(sum<w){puts("No Solution");return 0;}
else if(sum==w)
{
for(int i=0;i<n;++i)
(i==n-1)?printf("%d\n",a[i]):printf("%d ",a[i]);
return 0;
}
f=0;dfs(0);
if(!f)puts("No Solution");
else
for(int i=0;i<t.size();++i)
(i==t.size()-1)?printf("%d\n",t[i]):printf("%d ",t[i]);
}
L3-002 特殊堆栈 (30 分)(二分)
【分析】如果不用二分直接数组或vector拷贝会超时;二分找到元素位置,再执行删除或插入操作
【代码】
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
int a[maxn];
vector<int>v;
vector<int>::iterator it;
int main()
{
int n;scanf("%d",&n);
int cnt=0;
while(n--)
{
string s;cin>>s;
if(s=="Push")
{
int x;scanf("%d",&x);
a[cnt++]=x;
it=lower_bound(v.begin(),v.end(),x);
v.insert(it,x);
}
else if(s=="Pop")
{
if(cnt>0)
{
it=lower_bound(v.begin(),v.end(),a[cnt-1]);
v.erase(it);
printf("%d\n",a[--cnt]);
}
else puts("Invalid");
}
else if(s=="PeekMedian")
{
if(cnt==0)puts("Invalid");
else
{
int x=v.size();
if(x&1)printf("%d\n",v[x/2]);
else printf("%d\n",v[x/2-1]);
}
}
}
}
L3-003 社交集群 (30 分)(并查集)
【分析】并查集,注意map是按键值排序的,如果用it->second的话并不是有序输出的;所以存数组里排个序好啦
【代码】
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e3+10;
int pre[maxn];
vector<int>v[maxn];
int mp[maxn];
int n;
bool cmp(int x,int y){return x>y;}
int finds(int x){return pre[x]==x?x:pre[x]=finds(pre[x]);}
void join(int x,int y)
{
int fx=finds(x),fy=finds(y);
if(fx!=fy)
pre[fx]=fy;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;++i)pre[i]=i;
int maxx=-1;
for(int i=1;i<=n;++i)
{
int k;scanf("%d: ",&k);
for(int j=0;j<k;++j)
{
int x;scanf("%d",&x);
v[x].push_back(i);
maxx=max(maxx,x);
}
}
for(int i=1;i<=maxx;++i)
{
int x;
if(v[i].size())x=v[i][0];
for(int j=1;j<v[i].size();++j)
join(x,v[i][j]);
}
int cnt=0;
for(int i=1;i<=n;++i)
{
int fx=finds(i);
if(!mp[fx])cnt++;
mp[fx]++;
}
printf("%d\n",cnt);
sort(mp,mp+maxn,cmp);
for(int i=0;i<cnt;++i)
(i==cnt-1)?printf("%d\n",mp[i]):printf("%d ",mp[i]);
}
L3-004 肿瘤诊断 (30 分)(三维bfs)
【分析】注意这个肿瘤块是立体的!上下左右前后共六个方位。我一开始用的是二维的8个方位总是2个测试点答案错误....太蠢了太蠢了
【代码】
#include<bits/stdc++.h>
using namespace std;
const int maxn=1300;
int mp[70][maxn][140];
int vis[70][maxn][140];
int dir[6][3]={{0,0,1},{0,0,-1},{0,-1,0},{0,1,0},{-1,0,0},{1,0,0}};
int m,n,l,t,cnt;
struct node{
int z,x,y;
};
void bfs(int z,int x,int y)
{
if(mp[z][x][y]==1)cnt++;
queue<node>q;
q.push({z,x,y});
vis[z][x][y]=1;
while(!q.empty())
{
node t=q.front();
q.pop();
for(int i=0;i<6;++i)
{
z=t.z+dir[i][0];
x=t.x+dir[i][1];
y=t.y+dir[i][2];
if(x<0 || x>=m || y<0 || y>=n || z<0 || z>l || vis[z][x][y] || mp[z][x][y]==0)continue;
if(mp[z][x][y]==1)q.push({z,x,y});
cnt++;vis[z][x][y]=1;
}
}
}
int main()
{
scanf("%d%d%d%d",&m,&n,&l,&t);
int sum=0;
for(int k=0;k<l;++k)
for(int i=0;i<m;++i)
for(int j=0;j<n;++j)
scanf("%d",&mp[k][i][j]);
memset(vis,0,sizeof(vis));
for(int k=0;k<l;++k)
for(int i=0;i<m;++i)
{
for(int j=0;j<n;++j)
{
if(mp[k][i][j] && !vis[k][i][j])bfs(k,i,j);
if(cnt>=t)sum+=cnt;
cnt=0;
}
}
printf("%d\n",sum);
}
L3-016 二叉搜索树的结构 (30 分)(数组+字符串+函数定义+不用定义树结构的)
【分析】
不用定义结构体,直接用数组来做;l[i] & r[i]分别代表节点i的左右节点的下标;
deep数组存每个节点对应的index的深度;
mp存每个值的对应的下标
因为上面的数组的值对应的都是下标,所以要用map存一下;
【代码】
#include<bits/stdc++.h>
using namespace std;
const int maxn=110;
int a[maxn],l[maxn],r[maxn];
int pre[maxn],deep[maxn];
map<int,int>mp;
int n,q;
int root;
void insert(int &Root,int fa,int dep,int id)
{
// cout<<l[Root]<<","<<r[Root]<<endl;
if(Root==-1)
{
Root=id;//这里就是给l,r数组赋值;如果是-1那么会走这个if语句,然后赋值返回
pre[id]=fa;
deep[id]=dep;
return;
}
if(a[id]<a[Root])insert(l[Root],Root,dep+1,id);
else insert(r[Root],Root,dep+1,id);
}
int main()
{
scanf("%d",&n);
memset(l,-1,sizeof(l));
memset(r,-1,sizeof(r));
root=-1;
for(int i=1;i<=n;++i)
{
scanf("%d",&a[i]);
insert(root,-1,1,i);
mp[a[i]]=i;
}
scanf("%d",&q);getchar();
while(q--)
{
string s;getline(cin,s);
int x,y,f=0;
if(s.find("root")!=string::npos)
{
sscanf(s.c_str(),"%d is the root",&x);
if(mp.find(x)!=mp.end() && a[root]==x)f=1;
}
else if(s.find("siblings")!=string::npos)
{
sscanf(s.c_str(),"%d and %d are siblings",&x,&y);
if(mp.find(x)!=mp.end() && mp.find(y)!=mp.end() && pre[mp[x]]==pre[mp[y]])f=1;
}
else if(s.find("parent")!=string::npos)
{
sscanf(s.c_str(),"%d is the parent of %d",&x,&y);
if(mp.find(x)!=mp.end() && mp.find(y)!=mp.end() && pre[mp[y]]==mp[x])f=1;
}
else if(s.find("left")!=string::npos)
{
sscanf(s.c_str(),"%d is the left child of %d",&x,&y);
if(mp.find(x)!=mp.end() && mp.find(y)!=mp.end() && pre[mp[x]]==mp[y] && x<y)f=1;
}
else if(s.find("right")!=string::npos)
{
sscanf(s.c_str(),"%d is the right child of %d",&x,&y);
if(mp.find(x)!=mp.end() && mp.find(y)!=mp.end() && pre[mp[x]]==mp[y] && x>y)f=1;
}else if(s.find("same")!=string::npos)
{
sscanf(s.c_str(),"%d and %d are on the same level",&x,&y);
if(mp.find(x)!=mp.end() && mp.find(y)!=mp.end() && deep[mp[x]]==deep[mp[y]])f=1;
}
if(f)puts("Yes");
else puts("No");
}
}
L3-005 垃圾箱分布 (30 分)(dijkstra)
【分析】和pat甲级一道题类似;把垃圾箱的下标转换成n之后的数,然后求出单源最短路径即可;
排序的话,是按照最短路径->最小平均值->最小下标
【代码】
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e3+20;
const int inf=0x3f3f3f3f;
int e[maxn][maxn];
int vis[maxn],dis[maxn];
int n,m,k,d;
void dijkstra(int x)
{
memset(dis,inf,sizeof(dis));
memset(vis,0,sizeof(vis));
dis[x]=0;
for(int i=1;i<=m+n;++i)
{
int now=-1,minn=inf;
for(int j=1;j<=m+n;++j)
if(!vis[j] && dis[j]<minn)
minn=dis[j],now=j;
if(now==-1)break;
vis[now]=1;
for(int j=1;j<=m+n;++j)
if(!vis[j] && dis[now]+e[now][j]<dis[j])
dis[j]=e[now][j]+dis[now];
}
}
int main()
{
memset(e,inf,sizeof(e));
scanf("%d%d%d%d",&n,&m,&k,&d);
while(k--)
{
string s1,s2;cin>>s1>>s2;
int dist;scanf("%d",&dist);
if(dist>d)continue;
int x,y;
if(s1[0]=='G')x=stoi(s1.substr(1))+n;
else x=stoi(s1);
if(s2[0]=='G')y=stoi(s2.substr(1))+n;
else y=stoi(s2);
e[x][y]=e[y][x]=dist;
}
int maxx=0,sum=0,f=0,id;
for(int i=n+1;i<=n+m;++i)
{
dijkstra(i);
f=0;
int mind=inf,sum1=0;
for(int j=1;j<=n;++j)
{
if(dis[j]>d){sum1=-1;break;}
sum1+=dis[j];
mind=min(mind,dis[j]);
}
if(sum1!=-1)
{
f=1;
if(mind>minn)maxx=mind,id=i,sum=sum1;
else if(mind==maxx && sum1<sum)sum=sum1,id=i;
}
}
if(!f)puts("No Solution");
else
printf("G%d\n%.1lf %.1lf\n",id-n,maxx*1.0,sum*1.0/n);
return 0;
}
L3-013 非常弹的球 (30 分)(物理公式水题)
【分析】其实刚看到这题我是拒绝的...因为是物理题
不过再看 发现其实是很基础的物理题啦,而且公式都给出来了,再推下就好了
【代码】
#include<bits/stdc++.h>
using namespace std;
const double esp=0.0001;
int main()
{
double g=9.8;
double e=1000;
double res=0;
double w,p;scanf("%lf%lf",&w,&p);
w/=100;
p=(100-p)/100;
double v=1;
while(v>esp)
{
v=sqrt(2*e/w);
double vy=v*sqrt(2)/2;
double t=vy/g;
res+=vy*t*2;
e*=p;
}
printf("%.3lf\n", res);
return 0;
}