题解:P15119 [ICPC 2024 LAC] Expanding STACKS!
前言:真有这样的店吗,我好想去!
题意
题目描述得非常清晰了,我来大概总结一下。
输入给出顾客的出入情况,顾客后进先出。有两个队伍可以站,分别对应 G 和 S,要求我们给出合法的分配方式,否则输出字符 "*"。
思路
很明显,由于后进先出,两个队伍就是两个栈。接下来,我们又可以把顾客的在队时间看成一个区间。所以,若要合法,我们就要使栈中的区间不交叉。 ::::info[什么情况不交叉呢?]
- 完全不在一起,即满足
x_{出队}<y_{入队} 。 - 嵌套,即第 x 人和 第 y 人满足
x_{出队}<y_{出队} 并且x_{入队}>y_{出队} 。 ::::
那么,聪明的小朋友就要问了,相交呢?
很明显,若相交,他们肯定不能站在一个栈中,就要去另一边。我们可以通过对区间染色的方式来标记人所处的队列。
首先先得处理顾客之间是否相交的问题,枚举顾客两两讨论,判断区间是否相交,若相交,可以用一个 vector 数组记录两人区间相交。
然后,再枚举一遍顾客,若未染色,进行染色,并为与之区间相交的顾客染不同的颜色并继续访问其相交顾客(有点绕?代码里面会有注释,可能容易理解一些)。
最后不同的颜色输出 G 和 S 即可。 ::::info[那什么是无解情况呢?] 若顾客对区间相交的顾客染色时,发现对方已被染色且颜色相同,说明无解了。 ::::代码
#include<bits/stdc++.h> using namespace std; int n; int man[1005][2];//记录顾客的出入时间 vector<int> sp[1005]; int clr[1005]; bool flag=1; bool jiao_cha(int x,int y){ int lx=man[x][0],rx=man[x][1]; int ly=man[y][0],ry=man[y][1]; //完全分离无交集 if(rx<ly||ry<lx){ return 0; } //互相嵌套包含 if((lx<ly&&ry<rx)||(ly<lx&&rx<ry)){ return 0; } //交叉互斥 return 1; } bool pt(int x){//返回false说明无解 queue<int> q; q.push(x); if(!clr[x]){//未染色 clr[x]=1; } while(!q.empty()){ int now=q.front(); q.pop(); for(int v : sp[now]){//染色与之区间相交的顾客 if(!clr[v]){ clr[v]=(clr[now]==1?2:1); q.push(v);//再讨论 }else if(clr[v]==clr[now]){//无解情况 return 0; } } } return 1; } int main(){ ios::sync_with_stdio(0);//关流,数据小可有可无 cin.tie(0);cout.tie(0); cin>>n; for(int i=1;i<=2*n;++i){ int po; cin>>po; if(po>0){//进入时间 man[po][0]=i; }else{//出去时间 man[-po][1]=i; } } for(int i=1;i<=n;++i){ for(int j=i+1;j<=n;++j){ if(jiao_cha(i,j)){//判断是否区间相交 sp[i].push_back(j); sp[j].push_back(i); } } } for(int i=1;i<=n;++i){ if(clr[i]==0){ if(!pt(i)){ flag=0;//标记无解 break; } } } if(flag){ for(int i=1;i<=n;++i){ cout<<(clr[i]==1?'G':'S'); } }else{ cout<<'*'; } return 0; }求管理大大过一下,辛苦啦!qwq