Peaceful Commission
题意
委员会由若干议员组成,且必须满足:
- 对于每个党派,在委员会中恰好有 1 1 1 名代表(每个党派恰好有 2 2 2 个代表)
- 如果两名议员互不喜欢,他们不能同时加入委员会
决定是否能组成委员会,如果可以,输出字典序最小的方式
思路
按照 2 − S A T 2-SAT 2−SAT 的方式建图,要求最小化答案字典序的话,我们可以先试一下反变量(编号更小的代表)可不可行,如果不可行,再试一下原变量,如果两个都不行(在同一个 S C C SCC SCC 中),那么显然无解
在 d f s dfs dfs 的过程中,用一个栈来保存当前这一轮访问过的点,以便回溯撤销 v i s vis vis 数组
这样子操作的话,每个连通块中的点最多只会访问两次,复杂度应该是线性的
// Problem: Peaceful Commission
// Contest: HDOJ
// URL: https://acm.hdu.edu.cn/showproblem.php?pid=1814
// Memory Limit: 32 MB
// Time Limit: 10000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include<bits/stdc++.h>
#define fore(i,l,r) for(int i=(int)(l);i<(int)(r);++i)
#define fi first
#define se second
#define endl '\n'
#define ull unsigned long long
const int INF=0x3f3f3f3f;
const long long INFLL=0x3f3f3f3f3f3f3f3fLL;
typedef long long ll;
std::vector<std::vector<int>> g;
std::vector<bool> vis;
int n, m;
std::stack<int> stk;
bool dfs(int u){
if(vis[u ^ 1]) return false;
if(vis[u]) return true;
stk.push(u);
vis[u] = true;
for(auto v : g[u])
if(!dfs(v))
return false;
return true;
}
void solve(){
g.assign(2 * n + 1, std::vector<int>());
vis.assign(2 * n + 1, false);
fore(i, 0, m){
int u, v;
std::cin >> u >> v;
--u;
--v;
g[u].push_back(v ^ 1);
g[v].push_back(u ^ 1);
}
fore(i, 0, n){
if(vis[i << 1] || vis[i << 1 | 1]) continue;
while(!stk.empty()) stk.pop(); //这里必须清空,否则虽然不连通
//但是会影响最终答案,因为原本true的变量设成了false,导致cout出错
if(!dfs(i << 1)){
while(!stk.empty()){ //选小的那个不行
vis[stk.top()] = false;
stk.pop();
}
if(!dfs(i << 1 | 1)){ //选大的也不行
std::cout << "NIE\n";
return;
}
}
}
fore(i, 0, n){
std::cout << (vis[2 * i] ? 2 * i + 1 : 2 * i + 2) << endl;
}
}
int main(){
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
while(std::cin >> n >> m){
solve();
}
return 0;
}
/*
https://acm.hdu.edu.cn/showproblem.php?pid=1814
*/
/*
https://vjudge.net.cn/problem/HDU-1814
*/