有一堆夫妇,然后有两边,同一对夫妇不能在同一边。
同时再给出一些条件,就是不能让某两个人同时在左边。
问你是否有成立的情况,然后如果有,输出其中一种合法的方案。
婚礼 / Wedding
题目大意
有一堆夫妇,然后有两边,同一对夫妇不能在同一边。
同时再给出一些条件,就是不能让某两个人同时在左边。
问你是否有成立的情况,然后如果有,输出其中一种合法的方案。
思路
首先,你看到题目,自然会想到用 2-set 来做。
然后你考虑建边,对于每一对,有男的在新郎旁边和女的在新郎旁边。
然后如果有冲突,就互相连到互相的另一半。
然后这里有个关键的点就是新娘要连一条边到新郎。
为什么呢?
那你想,只有新郎是有限制的,新娘这边就是随便坐。
那我们 2-set 肯定要让电脑找的是新郎的这边啊。
那怎么弄呢?我们就可以这样连边,这样如果选了新娘就一定要选新郎,就会出现错误。但如果徐娜了新郎就不会有锅。
然后我们来看看怎么找答案 。
2-set 找答案是利用拓扑序,然后还是逆拓扑序,因为按逆的就不会产生冲突,不用逆的有可能会跟前面已经排好的产生冲突。
然后你会发现逆拓扑序其实就是你缩点的顺序,那就不用再跑一遍求了。
然后怎么通过逆拓扑序看放那边呢?
因为你 2-set 选的是新郎的,答案是要新娘的,我们只要到时反过来即可。
然后现在说的是新郎那边的。
那如果对于某一对,那它两个点会各有逆拓扑序。那你肯定是先处理逆拓扑序前的,也就是拓扑序后的,那就选这个点所对应的。
(记得在这道题要反过来!!!)
然后就可以了。
代码
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
struct node {
int to, nxt;
}e[500010];
int n, m, x, y, le[5001], KK;
char cx, cy, answer[5001];
int dfn[5001], low[5001], tmp;
int sta[5001], in[5001], n_n;
bool cant;
void csh() {
memset(e, 0, sizeof(e));
memset(le, 0, sizeof(le));
KK = 0;
memset(dfn, 0, sizeof(dfn));
memset(low, 0, sizeof(low));
tmp = 0;
memset(sta, 0, sizeof(sta));
memset(in, 0, sizeof(in));
n_n = 0;
cant = 0;
}
void add(int x, int y) {
e[++KK] = (node){y, le[x]}; le[x] = KK;
}
int another(int x) {
if (x > n) return x - n;
return x + n;
}
void tarjan(int now) {
dfn[now] = low[now] = ++tmp;
sta[++sta[0]] = now;
for (int i = le[now]; i; i = e[i].nxt)
if (!dfn[e[i].to]) {
tarjan(e[i].to);
low[now] = min(low[now], low[e[i].to]);
}
else if (!in[e[i].to]) low[now] = min(low[now], low[e[i].to]);
if (dfn[now] == low[now]) {
in[now] = ++n_n;
while (sta[sta[0]] != now) {
in[sta[sta[0]]] = n_n;
sta[0]--;
}
sta[0]--;
}
return ;
}
int main() {
scanf("%d %d", &n, &m);
while (n || m) {
csh();
for (int i = 1; i <= m; i++) {
scanf("%d%c %d%c", &x, &cx, &y, &cy);
x++;
y++;
if (cx == 'h') x += n;
if (cy == 'h') y += n;
add(x, another(y));
add(y, another(x));
}
add(1, 1 + n);
for (int i = 1; i <= 2 * n; i++)
if (!dfn[i]) tarjan(i);
for (int i = 1; i <= n; i++)
if (in[i] == in[n + i]) {
cant = 1;
printf("bad luck\n");
break;
}
if (cant) {
scanf("%d %d", &n, &m);
continue;
}
for (int i = 2; i <= n; i++) {
printf("%d", i - 1);
if (in[i] > in[i + n]) printf("w");
else printf("h");
printf(" ");
}
printf("\n");
scanf("%d %d", &n, &m);
}
return 0;
}
__EOF__
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现