看到HDOJ上有一個2-SAT專題,刷完之後順便總結一下。
最簡單的2-SAT問題就是判斷是否有解,回答YES或NO就行了,不需要輸出具體的解。這種問題建圖完畢後一個SCC(強連通分量)就好了。如果要輸出解,就多一個拓撲排序。代碼中涉及多次建圖,注意細節就好了。
1.HDOJ 3062 Party
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define mp make_pair
#define MEMSET(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef unsigned int ui;
typedef long long ll;
typedef unsigned long long ull;
typedef pair pii;
typedef vector vi;
typedef vi::iterator vi_it;
typedef map mii;
typedef priority_queue pqi;
typedef priority_queue, greater > rpqi;
const int MAX_N = 2000 + 10;
int link[MAX_N][MAX_N], rlink[MAX_N][MAX_N];
int stk[MAX_N];
bool vis[MAX_N];
int belong[MAX_N];
int top, cnt;
void dfs_visit(int (*lk)[MAX_N], int u, bool ft)
{
vis[u] = true;
for (int i = 1; i <= lk[u][0]; ++i) {
if (!vis[lk[u][i]]) {
dfs_visit(lk, lk[u][i], ft);
}
}
if (ft) {
stk[top++] = u;
}
else {
belong[u] = cnt;
}
}
void scc(int n)
{
top = 0;
MEMSET(vis, 0);
for (int i = 0; i < n; ++i) {
if (!vis[i]) {
dfs_visit(link, i, true);
}
}
cnt = 0;
MEMSET(vis, 0);
while (top) {
if (!vis[stk[--top]]) {
dfs_visit(rlink, stk[top], false);
++cnt;
}
}
}
bool two_sat(int n)
{
scc(n << 1);
for (int i = 0; i < n; ++i) {
if (belong[i] == belong[i + n]) {
return false;
}
}
return true;
}
int main(int argc, char *argv[])
{
int n, m, i, a1, a2, c1, c2;
while (cin >> n >> m) {
for (i = 0; i < (n << 1); ++i) {
rlink[i][0] = link[i][0] = 0;
}
while (m--) {
scanf("%d%d%d%d", &a1, &a2, &c1, &c2);
int b1 = a1 + n * (c1 ^ 1);
int b2 = a2 + n * (c2 ^ 1);
a1 += n * c1;
a2 += n * c2;
link[a1][++link[a1][0]] = b2;
link[a2][++link[a2][0]] = b1;
rlink[b2][++rlink[b2][0]] = a1;
rlink[b1][++rlink[b1][0]] = a2;
}
if (two_sat(n)) {
puts("YES");
}
else {
puts("NO");
}
}
return 0;
}
這個題要求輸出一組解,另外需要根據區間的交來建圖,代碼比較長。判斷區間是否相交時我先排序,這樣內層循環不用遍歷所有j,不過效率其實差不多,只快了一點點。。。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define mp make_pair
#define X first
#define Y second
#define MEMSET(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef unsigned int ui;
typedef long long ll;
typedef unsigned long long ull;
typedef pair pii;
typedef vector vi;
typedef vi::iterator vi_it;
typedef map mii;
typedef priority_queue pqi;
typedef priority_queue, greater > rpqi;
const int MAX_N = 2000 + 10;
int link[MAX_N][MAX_N], rlink[MAX_N][MAX_N];
int stk[MAX_N], ans[MAX_N], op[MAX_N];
bool vis[MAX_N], flag[MAX_N][MAX_N];
int belong[MAX_N];
int top, cnt;
pair cere[MAX_N];
void dfs_visit(int (*lk)[MAX_N], int u, bool ft)
{
vis[u] = true;
for (int i = 1; i <= lk[u][0]; ++i) {
if (!vis[lk[u][i]]) {
dfs_visit(lk, lk[u][i], ft);
}
}
if (ft) {
stk[top++] = u;
}
else {
belong[u] = cnt;
}
}
void scc(int n)
{
top = 0;
MEMSET(vis, 0);
for (int i = 0; i < n; ++i) {
if (!vis[i]) {
dfs_visit(link, i, true);
}
}
cnt = 0;
MEMSET(vis, 0);
while (top) {
if (!vis[stk[--top]]) {
dfs_visit(rlink, stk[top], false);
++cnt;
}
}
}
bool two_sat(int n)
{
scc(n << 1);
for (int i = 0; i < n + n; i += 2) {
if (belong[i] == belong[i + 1]) {
return false;
}
}
return true;
}
void color(int u)
{
ans[u] = 2;
for (int i = 1; i <= rlink[u][0]; ++i) {
if (!ans[rlink[u][i]]) {
color(rlink[u][i]);
}
}
}
bool cmp(const pair &p1, const pair &p2)
{
return p1.Y < p2.Y;
}
int main(int argc, char *argv[])
{
// freopen("D:\\in.txt", "r", stdin);
int n, i, j;
cin >> n;
for (i = 0; i < n; ++i) {
int s1, s2, t1, t2, d;
scanf("%d:%d %d:%d %d", &s1, &s2, &t1, &t2, &d);
cere[i + i] = mp(mp(s1 * 60 + s2, s1 * 60 + s2 + d), i + i);
cere[i + i + 1] = mp(mp(t1 * 60 + t2 - d, t1 * 60 + t2), i + i + 1);
}
sort(cere, cere + n + n);
for (i = 0; i < n + n; ++i) {
for (j = i + 1; j < n + n && cere[j].X.X < cere[i].X.Y; ++j) {
int u = cere[i].Y, v = cere[j].Y ^ 1;
if (!flag[u][v]) {
flag[u][v] = true;
link[u][++link[u][0]] = v;
rlink[v][++rlink[v][0]] = u;
}
u = cere[j].Y, v = cere[i].Y ^ 1;
if (!flag[u][v]) {
flag[u][v] = true;
link[u][++link[u][0]] = v;
rlink[v][++rlink[v][0]] = u;
}
}
}
if (!two_sat(n)) {
puts("NO");
return 0;
}
else {
puts("YES");
}
MEMSET(flag, 0);
for (i = 0; i < n + n; ++i) {
rlink[i][0] = 0;
op[belong[i]] = belong[i ^ 1];
}
for (i = 0; i < n + n; ++i) {
int u = belong[i];
for (j = 1; j <= link[i][0]; ++j) {
int v = belong[link[i][j]];
if (u != v && !flag[v][u]) {
flag[v][u] = true;
rlink[v][++rlink[v][0]] = u;
}
}
}
MEMSET(vis, 0);
top = 0;
for (i = 0; i < cnt; ++i) {
if (!vis[i]) {
dfs_visit(rlink, i, true);
}
}
while (top) {
if (!ans[stk[--top]]) {
ans[stk[top]] = 1;
color(op[stk[top]]);
}
}
sort(cere, cere + n + n, cmp);
for (i = 0; i < n + n; ++i) {
if (ans[belong[i]] == 1) {
printf("%02d:%02d %02d:%02d\n", cere[i].X.X / 60, cere[i].X.X % 60,
cere[i].X.Y / 60, cere[i].X.Y % 60);
}
}
return 0;
}
#include
#include
const int maxn=10010;
int n, m, nxt[maxn], head[maxn], pnt[maxn], ne, e, a, b, a0, b0;
char c1, c2;
int nnxt[maxn], nhead[maxn], npnt[maxn];
int order[maxn], norder, id[maxn], v[maxn];
int ans[maxn], op[maxn];
void dfs(int d){
v[d] = 1;
for(int i=head[d]; i!=-1; i=nxt[i])
if(!v[pnt[i]])
dfs(pnt[i]);
order[norder++] = d;
}
void ndfs(int d, int k){
v[d] = 1;
id[d] = k;
for(int i=nhead[d]; i!=-1; i=nnxt[i])
if(!v[npnt[i]])
ndfs(npnt[i], k);
}
void addedge(int s, int t){
pnt[e] = t; nxt[e] = head[s]; head[s] = e++;
}
void addnedge(int t, int s){
npnt[ne] = s; nnxt[ne] = nhead[t]; nhead[t] = ne++;
}
void color(int d){
ans[d] = 2;
for(int i=head[d]; i!=-1; i=nxt[i])
if(!ans[pnt[i]])
color(pnt[i]);
}
int main(){
while(1){
norder = e = ne = 0;
memset(head, -1, sizeof head);
memset(nhead, -1, sizeof nhead);
scanf("%d%d", &n, &m);
if(!n&&!m)
break;
for(int i=0; i=0; --i)
if(!v[order[i]])
ndfs(order[i], k++);
int mark = 1;
for(int i=0; i=0; --i)
if(!ans[order[i]]){
ans[order[i]] = 1;
color(op[order[i]]);
}
for(int i=1; i
4.HDOJ 3715 Go Deeper
二分答案之後判斷2-SAT問題是否有解。SCC用tarjan寫的。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define mp make_pair
#define X first
#define Y second
#define MEMSET(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef unsigned int ui;
typedef long long ll;
typedef unsigned long long ull;
typedef pair pii;
typedef vector vi;
typedef vi::iterator vi_it;
typedef map mii;
typedef priority_queue pqi;
typedef priority_queue, greater > rpqi;
const int MAX_N = 20000 + 10;
int head[MAX_N];
int edge[MAX_N * 100][2];
int dfn[MAX_N], low[MAX_N];
int stk[MAX_N];
int belong[MAX_N];
int top, cnt, idx, edgecnt;
int a[MAX_N], b[MAX_N], c[MAX_N];
int N;
void dfs(int u)
{
dfn[u] = low[u] = ++idx;
stk[top++] = u;
int v;
for (int i = head[u]; i != -1; i = edge[i][1]) {
if (!dfn[v = edge[i][0]]) {
dfs(v);
low[u] = min(low[u], low[v]);
}
else if (!belong[v]) {
low[u] = min(low[u], dfn[v]);
}
}
if (dfn[u] == low[u]) {
belong[u] = ++cnt;
while (stk[--top] != u) {
belong[stk[top]] = cnt;
}
}
}
void tarjan(int n)
{
MEMSET(belong, 0);
MEMSET(dfn, 0);
cnt = idx = top = 0;
for (int i = 1; i <= n; ++i) {
if (!dfn[i]) {
dfs(i);
}
}
}
bool two_sat(int n)
{
tarjan(n + n);
for (int i = 1; i <= n; ++i) {
if (belong[i] == belong[i + n]) {
return false;
}
}
return true;
}
inline void add_edge(int u, int v)
{
edge[edgecnt][0] = v;
edge[edgecnt][1] = head[u];
head[u] = edgecnt++;
}
void build(int n)
{
int i;
MEMSET(head, -1);
edgecnt = 0;
for (i = 1; i <= n; ++i) {
if (c[i] == 0) {
add_edge(a[i], b[i] + N);
add_edge(b[i], a[i] + N);
}
else if (c[i] == 1) {
add_edge(a[i], b[i]);
add_edge(b[i], a[i]);
add_edge(a[i] + N, b[i] + N);
add_edge(b[i] + N, a[i] + N);
}
else {
add_edge(a[i] + N, b[i]);
add_edge(b[i] + N, a[i]);
}
}
}
int main(int argc, char *argv[])
{
// freopen("D:\\in.txt", "r", stdin);
int t, n, m, i, j;
cin >> t;
while (t--) {
scanf("%d%d", &n, &m);
N = n;
for (i = 1; i <= m; ++i) {
scanf("%d%d%d", a + i, b + i, c + i);
}
int low = 0, high = m, ans = 0;
while (low <= high) {
int mid = (low + high) >> 1;
build(mid);
if (two_sat(N)) {
low = mid + 1;
ans = mid;
}
else {
high = mid - 1;
}
}
printf("%d\n", ans);
}
return 0;
}
5.POJ 3207 Ikki's Story IV - Panda's Trick
也是只需要判斷,不過注意弦相交的判斷方法。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define mp make_pair
#define MEMSET(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef unsigned int ui;
typedef long long ll;
typedef unsigned long long ull;
typedef pair pii;
typedef vector vi;
typedef vi::iterator vi_it;
typedef map mii;
typedef priority_queue pqi;
typedef priority_queue, greater > rpqi;
const int MAX_M = 1000 + 2;
int line[MAX_M][2];
vector link[MAX_M];
int dfn[MAX_M], low[MAX_M], belong[MAX_M];
int stk[MAX_M];
int cnt = 0, top = 0, idx = 0;
bool intersect(int *a, int *b, int n)
{
if (a[0] < b[0] && b[0] < a[1] && a[1] < b[1]) {
return true;
}
if (b[0] < a[0] && a[0] < b[1] && b[1] < a[1]) {
return true;
}
return false;
}
void dfs(int u)
{
dfn[u] = low[u] = ++idx;
stk[top++] = u;
int v;
for (int i = 0; i < link[u].size(); ++i) {
if (!dfn[v = link[u][i]]) {
dfs(v);
low[u] = min(low[u], low[v]);
}
else if (!belong[v]) {
low[u] = min(low[u], dfn[v]);
}
}
if (dfn[u] == low[u]) {
belong[u] = ++cnt;
while (stk[--top] != u) {
belong[stk[top]] = cnt;
}
}
}
void tarjan(int n)
{
for (int i = 0; i < n; ++i) {
if (!dfn[i]) {
dfs(i);
}
}
}
bool two_sat(int n)
{
tarjan(n + n);
for (int i = 0; i < n; ++i) {
if (belong[i] == belong[i + n]) {
return false;
}
}
return true;
}
int main(int argc, char *argv[])
{
// freopen("D:\\in.txt", "r", stdin);
int n, m;
cin >> n >> m;
for (int i = 0; i < m; ++i) {
cin >> line[i][0] >> line[i][1];
if (line[i][0] > line[i][1]) {
swap(line[i][0], line[i][1]);
}
for (int j = 0; j < i; ++j) {
if (intersect(line[i], line[j], n)) {
link[i].push_back(j + m);
link[j].push_back(i + m);
link[i + m].push_back(j);
link[j + m].push_back(i);
}
}
}
if (two_sat(m)) {
puts("panda is telling the truth...");
}
else {
puts("the evil panda is lying again");
}
return 0;
}