题目大意
有n种颜色,每种颜色有2个小球,现在将这2n个小球分别放到m个容器里,当两个容器的顶部小球颜色相同时,可以把这两个小球拿出容器,问可不可能把2n个小球从m个容器中拿出来。
思路
因为每个容器的小球是满足先输入的先出容器的,所以用m个队列存每个容器里小球的情况。
用一个数组vis[ i ]记录当前第 i 种颜色的小球是否出现过在某个容器的顶部,再用一个map记录当前第 i 种颜色的小球第一次出现在哪个容器的顶部。
枚举每一个容器,如果容器 i 的顶部小球对应的颜色出现过,即vis[ ] = 1的话,用map找到顶部小球对应颜色第一次出现的容器,删除该容器和容器 i 的顶部小球,并对两个容器继续重复判断顶部小球对应的颜色是否出现过。
这种方法的时间复杂度是O(n)的,但是空间复杂度会很大,不过还是能满足题目要求的。
#include <bits/stdc++.h>
using namespace std;
const long long INF = 0x3f3f3f3f3f3f3f3fLL;
unordered_map<int, int>mp;
queue<int> q[200005];
int vis[200005];
void dfs(int i)
{
int pos = mp[q[i].front()];
q[pos].pop();
q[i].pop();
while(!q[pos].empty() && vis[q[pos].front()])
{
dfs(pos);
}
if(!q[pos].empty())
{
vis[q[pos].front()] = 1;
mp[q[pos].front()] = pos;
}
}
int main()
{
int n, m;
scanf("%d%d", &n, &m);
memset(vis, 0, sizeof(vis));
for(int i = 1; i <= m; i++)
{
int k;
scanf("%d", &k);
while(k--)
{
int a;
scanf("%d", &a);
q[i].push(a);
}
}
for(int i = 1; i <= m; i++)
{
while(!q[i].empty() && vis[q[i].front()])
{
dfs(i);
}
if(!q[i].empty()) //记录栈顶元素时记得不要越界了
{
vis[q[i].front()] = 1;
mp[q[i].front()] = i;
}
}
int flag = 0;
for(int i = 1; i <= m; i++)
{
if(!q[i].empty()) //如果所有的队列都为空,说明全部小球都拿出来了
{
flag = 1;
break;
}
}
if(flag)
{
printf("No\n");
}
else
{
printf("Yes\n");
}
return 0;
}