题面
有n对夫妻被邀请参加一个聚会,因为场地的问题,每对夫妻中只有1人可以列席。在2n 个人中,某些人之间有着很大的矛盾(当然夫妻之间是没有矛盾的),有矛盾的2个人是不会同时出现在聚会上的。有没有可能会有n 个人同时列席?
题解
发发两者不能同时出现,符合2-SAT模型,因为m的数据过大,所以常规的dfs算法的O(n(n+m))的复杂度不能承受。
又其提问为是否存在最大解,故将原问题建图并求强连通分量,根据点与点之间关系可以直接得出答案。
考虑建图,因为一对夫妻之间相互排斥且要求至少有一人入选,所以可以考虑将夫妻作为原建图习惯中的排斥点来建图,即选了A后就不能选A的对象;不选A则一定要选A的对象。
代码
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cstdlib>
using namespace std;
const int maxn = 2e3+100;
const int maxm = 5e6+10;
int fi[maxn], ecnt;
int dfn[maxn], low[maxn], st[maxn], bel[maxn];
//bel -> belong;
int n, m, top, bcnt, bnum;
//bnum -> 时间戳;
bool vis[maxn];
struct Edge {
int v, next;
}e[maxm];
void add_edge(int u, int v) {
e[ecnt] = (Edge){v, fi[u]};
fi[u] = ecnt++;
}
void init() {
memset(fi, -1, sizeof(fi));
memset(dfn, 0, sizeof(dfn));
ecnt = top = bnum = bcnt = 0;
}
void Tarjan(int x) {
dfn[x] = low[x] = ++bnum;
vis[x] = true;
st[++top] = x;
for(int i = fi[x]; i != -1; i = e[i].next) {
int v = e[i].v;
if(!dfn[v]) {
Tarjan(v);
low[x] = min(low[x], low[v]);
} else if(vis[v] && dfn[v] < low[x])
low[x] = dfn[v];
}
if(dfn[x] == low[x]) {
bel[x] = ++bcnt;
vis[x] = 0;
int v = st[top];
while(v != x) {
vis[v] = 0;
bel[v] = bcnt;
v = st[--top];
}
--top;
}
}
int main() {
bool flag = 0;
while(~scanf("%d%d", &n, &m)) {
flag = 1; init();
for(int i = 1; i <= m; i++) {
int x1, x2, y1, y2;
scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
add_edge(x1*2+x2, y1*2+!y2);
add_edge(y1*2+y2, x1*2+!x2);
}
for(int i = 0; i < n*2; i++) if(!dfn[i]) Tarjan(i);
for(int i = 0; i < n; i++)
if(bel[i*2] == bel[i*2+1]) {
printf("NO\n");
flag = 0;
break;
}
if(flag) printf("YES\n");
}
}
本文探讨了一个2-SAT问题的实例,即在有矛盾的人员中选择n对夫妻参加聚会的问题。通过构建图模型并利用强连通分量算法,有效地解决了是否存在满足条件的选择方案。文章详细介绍了建图过程、Tarjan算法的应用及最终的判断逻辑。
453

被折叠的 条评论
为什么被折叠?



