2024SMUSpring天梯2补题
L2-2:红色警报
题意:![](https://img2024.cnblogs.com/blog/3142690/202403/3142690-20240327100638483-1652480883.png)
![](https://img2024.cnblogs.com/blog/3142690/202403/3142690-20240327100654162-1763833720.png)
只要连通块数目减少就输出RedAlert,主要是连通块数目..
int n,m,k;
unordered_map<int,int> mark;
vector<int> vct[505];
bool vis[505];
void dfs(int x){
for(auto v:vct[x]){
if(!vis[v]&&!mark[v]){
vis[v]=1;
dfs(v);
}
}
}
void solve(){ //L2-2 ??---
// 题意理解错了,不是现有国家整体从连通到不连通才输出RedAlert。而是只要国家连通块增加了,就输出RedAlert..
cin>>n>>m;
for(int i=1;i<=m;i++){
int u,v;
cin>>u>>v;
vct[u].emplace_back(v);
vct[v].emplace_back(u);
}
cin>>k;
int cntBlock=0;
for(int i=0;i<n;i++) {
if(!vis[i]){
vis[i]=1;
dfs(i);
cntBlock++;
}
}
for(int i=1;i<=k;i++){
int bd; cin>>bd;
mark[bd]=1;
memset(vis,0,sizeof(vis));
int curcnt=0;
for(int j=0;j<n;j++){
if(!vis[j]&&!mark[j]){
dfs(j);
vis[j]=1;
curcnt++;
}
}
if(curcnt<=cntBlock) cout<<"City "<<bd<<" is lost."<<endl;
else cout<<"Red Alert: City "<<bd<<" is lost!"<<endl;
cntBlock=curcnt;
}
if(k==n) cout<<"Game Over.";
}
L2-3:排座位
题意:![](https://img2024.cnblogs.com/blog/3142690/202403/3142690-20240327100905353-495532293.png)
朋友关系可以传递,敌对关系不可以传递。
int fa[300];//1-100存朋友关系.101-200存敌对关系.---no!!敌对关系不会传递!!
int find(int x){
if(x!=fa[x]) fa[x]=find(fa[x]);
return fa[x];
}
void Union(int x,int y){
int fa1=find(x),fa2=find(y);
fa[fa1]=fa2;
}
void solve(){ //L2-3
//要用并查集,用map写的话只有22分,扣3分。。因为长的传递关系map识别不出来..
int n,m,k;
cin>>n>>m>>k;
for(int i=1;i<=100;i++) fa[i]=i;
unordered_set<int> hate[105];
for(int i=1;i<=m;i++){
int u,v,rela;
cin>>u>>v>>rela;
if(rela==-1){
hate[u].insert(v); //一个人敌对的人可能有多个
hate[v].insert(u);
}
else if(find(u)!=find(v)) Union(u,v);
}
while(k--){
int u,v; cin>>u>>v;
int frdu=find(u),frdv=find(v);
if((hate[u].find(v)!=hate[u].end())&&frdu==frdv) cout<<"OK but..."<<endl;
else if(hate[u].find(v)!=hate[u].end()) cout<<"No way"<<endl;
else if(frdu==frdv) cout<<"No problem"<<endl;
else cout<<"OK"<<endl;
}
}
L3-1:肿瘤诊断
题意:![](https://img2024.cnblogs.com/blog/3142690/202403/3142690-20240327203959661-815778788.png)
![](https://img2024.cnblogs.com/blog/3142690/202403/3142690-20240327204027629-1762775568.png)
题目的实现不难,三维bfs即可.但是一开始没理解图是怎么样的。如图所示,在某一个1的位置,即蓝色的位置。图可以通向上一层,和下一层,以及该层的东南西北,6个方向的1.题意就是数出这些连通块的1,大于等于t的才记录到ans.(即输入是一片一片从上往下输入的,每一片是m*n的,一共有L片)
int n,m,l,t,ans=0;
int maze[65][1300][130]; //三维的,有上,下,东南西北,6个方向
bool vis[65][1300][130];
typedef struct myp{
int f,xx,yy;
}myp;
int dx[4]={-1,1,0,0};
int dy[4]={0,0,-1,1};
void bfs(int f,int x0,int y0){
int cnt=0;
vis[f][x0][y0]=1;
queue<myp> que;
que.emplace(myp{f,x0,y0});
while(que.size()){ //看清楚ff和f...
int ff=que.front().f,xx=que.front().xx,yy=que.front().yy;
que.pop();
cnt++;
if(ff-1>=1&&maze[ff-1][xx][yy]==1&&!vis[ff-1][xx][yy]) que.emplace(myp{ff-1,xx,yy}),vis[ff-1][xx][yy]=1; //记得标记vis
if(ff+1<=l&&maze[ff+1][xx][yy]==1&&!vis[ff+1][xx][yy]) que.emplace(myp{ff+1,xx,yy}),vis[ff+1][xx][yy]=1;
for(int i=0;i<4;i++){
int x=xx+dx[i],y=yy+dy[i];
if(x>=1&&x<=n&&y>=1&&y<=m&&maze[ff][x][y]==1&&!vis[ff][x][y]){
que.emplace(myp{ff,x,y});
vis[ff][x][y]=1;
}
}
}
if(cnt>=t) ans+=cnt;
}
void solve(){ //L3-1 三维的bfs,不难
cin>>n>>m>>l>>t;
for(int f=1;f<=l;f++){
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>maze[f][i][j];
}
}
}
for(int f=1;f<=l;f++){
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(!vis[f][i][j]&&maze[f][i][j]==1){
bfs(f,i,j);
}
}
}
}
cout<<ans;
}
L3-3:特殊堆栈
题意:![](https://img2024.cnblogs.com/blog/3142690/202403/3142690-20240328220608130-573226419.png)
![](https://img2024.cnblogs.com/blog/3142690/202403/3142690-20240328220622713-1319340263.png)
思路:普通的两个优先队列对顶堆,不好实现删除操作。这题可以用两个multiset来维护数据,模拟对顶堆。也容易进行删除操作。就是有点绕,看清楚想明白就好。
void solve(){ //补L3-3 特殊堆栈
int n; cin>>n;
stack<int> stk;
multiset<int> mstbig,mstless; //模拟大根堆和小根堆
while(n--){
string str; cin>>str;
if(str=="Pop"){ //维护对顶堆的删除
if(stk.size()==0) cout<<"Invalid"<<endl;
else {
if(mstless.size()==mstbig.size()){
if(mstless.find(stk.top())!=mstless.end()){
mstless.erase(mstless.find(stk.top()));
mstless.emplace(*mstbig.rbegin());
mstbig.erase(mstbig.find(*mstbig.rbegin()));
}
else mstbig.erase(mstbig.find(stk.top()));
}
else if(mstless.size()>mstbig.size()){
if(mstless.find(stk.top())!=mstless.end()) mstless.erase(mstless.find(stk.top()));
else{
mstbig.erase(mstbig.find(stk.top()));
mstbig.emplace(*mstless.begin());
mstless.erase(mstless.find(*mstless.begin()));
}
}
cout<<stk.top()<<endl;
stk.pop();
}
}
else if(str=="PeekMedian"){
if(stk.size()==0) cout<<"Invalid"<<endl;
else if(mstless.size()==mstbig.size()) cout<<*mstbig.rbegin()<<endl; //n/2位置
else cout<<*mstless.begin()<<endl; //(n+1)/2位置
}
else{ //带删除元素操作的对顶堆维护
int x;cin>>x;
stk.emplace(x);
if(mstless.size()==0&&mstbig.size()==0) mstless.emplace(x);
else if(mstless.size()==mstbig.size()){ //两个堆大小相同-
if(x>=*mstbig.rbegin()) mstless.emplace(x); //大根堆size不可能为0
else{
mstless.emplace(*mstbig.rbegin());
mstbig.erase(mstbig.find(*mstbig.rbegin()));
mstbig.emplace(x);
}
}
else if(mstless.size()>mstbig.size()){ //小根堆多一个,一定只是多一个,是维护出来的
if(x<=*mstless.begin()) mstbig.emplace(x); //小根堆size不可能为0
else{
mstbig.emplace(*mstless.begin());
mstless.erase(mstless.find(*mstless.begin()));
mstless.emplace(x);
}
}
}
}
}