天天看点

2-SAT 题目整理

其实就是把kb菊苣整理的题目刷了一遍。

poj-3648 Wedding

细节:不让新娘看到有奸情的任意一对同时在对面一侧,则必选新郎,然后构造新郎那侧的可行解,然后将染相反颜色的人输出(要求输出新娘那侧的人)。

代码1(任意可行解):

#include <algorithm>
#include <iostream>
#include <string.h>
#include <vector>
#include <cstdio>
#include <queue> 
using namespace std;
const int maxn = 65;
const int maxm = maxn*maxn;
struct node {int u, v, next;} edge[maxm];
int no, head[maxn];
int dfn[maxn], low[maxn], index, sta[maxn], top;
bool vis[maxn];
int bel[maxn], cnt;
vector<int> g[maxn];
queue<int> q;
int opp[maxn], deg[maxn], col[maxn];
int n, m;
void init()
{
	no = 0;
	memset(head, -1, sizeof head);
	index = 0, top = 0;
	memset(dfn, 0, sizeof dfn);
	memset(vis, 0, sizeof vis);
	cnt = 0;
	memset(deg, 0, sizeof deg);
	memset(col, 0, sizeof col);
}
inline void add(int u, int v)
{
	edge[no].u = u; edge[no].v = v;
	edge[no].next = head[u]; head[u] = no++;
}
void tarjan(int u)
{
	dfn[u] = low[u] = ++index;
	sta[++top] = u, vis[u] = 1;
	for(int k = head[u]; k+1; k = edge[k].next)
	{
		int v = edge[k].v;
		if(!dfn[v])
		{
			tarjan(v);
			low[u] = min(low[u], low[v]);
		}
		else if(vis[v]) low[u] = min(low[u], dfn[v]);
	}
	if(dfn[u] == low[u])
	{
		++cnt;
		do
		{
			vis[sta[top]] = 0;
			bel[sta[top]] = cnt;
			--top;
		}
		while(sta[top+1] != u);
	}
}
void print()
{
	for(int i = 1; i < n; ++i)
	{
		if(i > 1) printf(" ");
		if(col[bel[i*2]] != 1) printf("%dh", i);
		if(col[bel[i*2+1]] != 1) printf("%dw", i);
	}
	printf("\n");
}
void topsort()
{
	for(int i = 1; i <= cnt; ++i) g[i].clear();
	for(int i = 0; i < no; ++i)
	{
		int u = edge[i].u, v = edge[i].v;
		if(bel[u] == bel[v]) continue;
		g[bel[v]].push_back(bel[u]);
		++deg[bel[u]];
	}
	while(!q.empty()) q.pop();
	for(int i = 1; i <= cnt; ++i)
	if(!deg[i]) q.push(i);
	while(!q.empty())
	{
		int u = q.front(); q.pop();
		if(!col[u])
		col[u] = 1, col[opp[u]] = -1;
		for(int i = 0; i < g[u].size(); ++i)
		{
			int v = g[u][i];
			if(--deg[v] == 0) q.push(v);
		}
	}
}
void work()
{
	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])
		{
			puts("bad luck");
			return;
		}
		else
		{
			opp[bel[i*2]] = bel[i*2+1];
			opp[bel[i*2+1]] = bel[i*2];
		} 
	}
	topsort();
	print();
}
void mapping()
{
	for(int i = 1; i <= m; ++i)
	{
		int u, v;
		char c1, c2;
		scanf("%d%c %d%c", &u, &c1, &v, &c2);
		u *= 2, v *= 2;
		if(c1 == 'w') ++u;
		if(c2 == 'w') ++v;
		add(u, (v^1));
		add(v, (u^1));
	}
	add(1, 0);
}
int main()
{
	while(~scanf("%d %d", &n, &m) && n+m)
	{
		init();
		mapping();
		work();
	}
	return 0;
}
           

代码2(字典序最小的解):

#include <algorithm>
#include <iostream>
#include <string.h>
#include <vector>
#include <cstdio>
#include <queue> 
using namespace std;
const int maxn = 65;
const int maxm = maxn*maxn;
struct node {int u, v, next;} edge[maxm];
int no, head[maxn];
int col[maxn], sta[maxn], top;
int n, m;
void init()
{
	no = 0;
	memset(head, -1, sizeof head);
	memset(col, 0, sizeof col);
}
inline void add(int u, int v)
{
	edge[no].u = u; edge[no].v = v;
	edge[no].next = head[u]; head[u] = no++;
}
void print()
{
	for(int i = 1; i < n; ++i)
	{
		if(i > 1) printf(" ");
		if(col[i*2] != 1) printf("%dh", i);
		if(col[i*2+1] != 1) printf("%dw", i);
	}
	printf("\n");
}
bool dfs(int u)
{
	if(col[u^1]) return 0;
	if(col[u]) return 1;
	col[u] = 1;
	sta[++top] = u;
	for(int k = head[u]; k+1; k = edge[k].next)
	{
		int v = edge[k].v;
		if(!dfs(v)) return 0;
	}
	return 1;
}
void work()
{
	for(int i = 0; i < n; ++i)
	{
		if(col[i*2] || col[i*2+1]) continue;
		top = 0;
		if(!dfs(i*2))
		{
			while(top) col[sta[top--]] = 0;
			if(!dfs(i*2+1))
			{
				puts("bad luck");
				return;
			}
		}
	}
	print();
}
void mapping()
{
	for(int i = 1; i <= m; ++i)
	{
		int u, v;
		char c1, c2;
		scanf("%d%c %d%c", &u, &c1, &v, &c2);
		u *= 2, v *= 2;
		if(c1 == 'w') ++u;
		if(c2 == 'w') ++v;
		add(u, (v^1));
		add(v, (u^1));
	}
	add(1, 0);
}
int main()
{
	while(~scanf("%d %d", &n, &m) && n+m)
	{
		init();
		mapping();
		work();
	}
	return 0;
}
           

hdu-1814 Peaceful Commission

输出字典序最小的解模板题。

代码:

#include <algorithm>
#include <iostream>
#include <string.h>
#include <vector>
#include <cstdio>
#include <queue> 
using namespace std;
const int maxn = 16005;
const int maxm = 40005;
struct node {int u, v, next;} edge[maxm];
int no, head[maxn];
int col[maxn], sta[maxn], top;
int n, m;
void init()
{
    no = 0;
    memset(head, -1, sizeof head);
    memset(col, 0, sizeof col);
}
inline void add(int u, int v)
{
    edge[no].u = u; edge[no].v = v;
    edge[no].next = head[u]; head[u] = no++;
}
void print()
{
    for(int i = 0; i < n; ++i)
    {
        if(col[i*2] == 1) printf("%d\n", i*2+1);
        if(col[i*2+1] == 1) printf("%d\n", i*2+1+1);
    }
}
bool dfs(int u)
{
    if(col[u^1]) return 0;
    if(col[u]) return 1;
    col[u] = 1;
    sta[++top] = u;
    for(int k = head[u]; k+1; k = edge[k].next)
    {
        int v = edge[k].v;
        if(!dfs(v)) return 0;
    }
    return 1;
}
void work()
{
    for(int i = 0; i < n; ++i)
    {
        if(col[i*2] || col[i*2+1]) continue;
        top = 0;
        if(!dfs(i*2))
        {
            while(top) col[sta[top--]] = 0;
            if(!dfs(i*2+1))
            {
                puts("NIE");
                return;
            }
        }
    }
    print();
}
void mapping()
{
    for(int i = 1; i <= m; ++i)
    {
        int u, v;
        scanf("%d %d", &u, &v);
        --u, --v;
        add(u, (v^1));
        add(v, (u^1));
    }
}
int main()
{
    //freopen("SPO.in", "r", stdin);
    //freopen("SPO.out", "w", stdout);
    while(~scanf("%d %d", &n, &m))
    {
        init();
        mapping();
        work();
    }
    return 0;
}
           

poj-3678 Katu Puzzle

抽象and、or、xor的冲突建图,求可行解。

代码:

#include <algorithm>
#include <iostream>
#include <string.h>
#include <vector>
#include <cstdio>
#include <queue> 
using namespace std;
const int maxn = 1005;
const int maxm = 4e6+5;
struct node {int u, v, next;} edge[maxm];
int no, head[maxn];
int dfn[maxn], low[maxn], index, sta[maxn], top;
bool vis[maxn];
int bel[maxn], cnt;
int n, m;
void init()
{
	no = 0;
	memset(head, -1, sizeof head);
	index = 0, top = 0;
	memset(dfn, 0, sizeof dfn);
	memset(vis, 0, sizeof vis);
	cnt = 0;
}
inline void add(int u, int v)
{
	edge[no].u = u; edge[no].v = v;
	edge[no].next = head[u]; head[u] = no++;
}
void tarjan(int u)
{
	dfn[u] = low[u] = ++index;
	sta[++top] = u, vis[u] = 1;
	for(int k = head[u]; k+1; k = edge[k].next)
	{
		int v = edge[k].v;
		if(!dfn[v])
		{
			tarjan(v);
			low[u] = min(low[u], low[v]);
		}
		else if(vis[v]) low[u] = min(low[u], dfn[v]);
	}
	if(dfn[u] == low[u])
	{
		++cnt;
		do
		{
			vis[sta[top]] = 0;
			bel[sta[top]] = cnt;
			--top;
		}
		while(sta[top+1] != u);
	}
}
void work()
{
	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])
		{
			puts("NO");
			return;
		}
	}
	puts("YES");
}
void mapping()
{
	for(int i = 1; i <= m; ++i)
	{
		int u, v, w;
		char s[5];
		scanf("%d %d %d%s", &u, &v, &w, s);
		u *= 2, v *= 2;
		if(s[0] == 'A')
		{
			if(w == 1) 
			add(u+1, v+1), add(v+1, u+1), add(u, u+1), add(v, v+1);
			else 
			add(u+1, v), add(v+1, u);
		}
		if(s[0] == 'O')
		{
			if(w == 1) 
			add(u, v+1), add(v, u+1);
			else 
			add(u, v), add(v, u), add(u+1, u), add(v+1, v);
		}
		if(s[0] == 'X')
		{
			if(w == 1) 
			add(u, v+1), add(v, u+1), add(v+1, u), add(u+1, v);
			else 
			add(u, v), add(v, u), add(u+1, v+1), add(v+1, u+1);
		}
	}
}
int main()
{
	while(scanf("%d %d", &n, &m) != EOF)
	{
		init();
		mapping();
		work();
	}
	return 0;
}
           

hdu-3622 Bomb Game

二分构图+可行性判断。

代码:

#include <algorithm>
#include <iostream>
#include <string.h>
#include <vector>
#include <cstdio>
#include <queue> 
#include <cmath>
using namespace std;
const double eps = 1e-5;
const int maxn = 205;
const int maxm = 4*maxn*maxn;
struct node {int u, v, next;} edge[maxm];
int no, head[maxn];
int dfn[maxn], low[maxn], index, sta[maxn], top;
bool vis[maxn];
int bel[maxn], cnt;
int n;
struct coordinate {int x, y;} a[2][maxn];
double dis[4][maxn][maxn];
void init()
{
    no = 0;
    memset(head, -1, sizeof head);
    index = 0, top = 0;
    memset(dfn, 0, sizeof dfn);
    memset(vis, 0, sizeof vis);
    cnt = 0;
}
inline void add(int u, int v)
{
    edge[no].u = u; edge[no].v = v;
    edge[no].next = head[u]; head[u] = no++;
}
void tarjan(int u)
{
    dfn[u] = low[u] = ++index;
    sta[++top] = u, vis[u] = 1;
    for(int k = head[u]; k+1; k = edge[k].next)
    {
        int v = edge[k].v;
        if(!dfn[v])
        {
            tarjan(v);
            low[u] = min(low[u], low[v]);
        }
        else if(vis[v]) low[u] = min(low[u], dfn[v]);
    }
    if(dfn[u] == low[u])
    {
        ++cnt;
        do
        {
            vis[sta[top]] = 0;
            bel[sta[top]] = cnt;
            --top;
        }
        while(sta[top+1] != u);
    }
}
bool work()
{
    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])
        return 0;
    }
    return 1;
}
bool mapping(double up)
{
    for(int i = 0; i < n; ++i)
    for(int j = i+1; j < n; ++j)
    {
        if(dis[0][i][j] <= up*up) add(i*2, j*2+1), add(j*2, i*2+1);
        
        if(dis[1][i][j] <= up*up) add(i*2, j*2), add(j*2+1, i*2+1);
        
        if(dis[2][i][j] <= up*up) add(i*2+1, j*2+1), add(j*2, i*2);
        
        if(dis[3][i][j] <= up*up) add(i*2+1, j*2), add(j*2+1, i*2);
    }
    return 1;
}
bool jg(double x)
{
    init();
    if(!mapping(x*2)) return 0;
    return work();
}
int main()
{
    //freopen("in.txt", "r", stdin);
    while(scanf("%d", &n) != EOF)
    {
        for(int i = 0; i < n; ++i)
        {
            scanf("%d %d", &a[0][i].x, &a[0][i].y);
            scanf("%d %d", &a[1][i].x, &a[1][i].y);
        }
        double t, l = 0, r = 0;
        for(int i = 0; i < n; ++i)
        for(int j = i+1; j < n; ++j)
        {
            t = (a[0][i].x-a[0][j].x)*(a[0][i].x-a[0][j].x);
            t += (a[0][i].y-a[0][j].y)*(a[0][i].y-a[0][j].y);
            dis[0][i][j] = t;
            r = max(r, sqrt(t));
            
            t = (a[0][i].x-a[1][j].x)*(a[0][i].x-a[1][j].x);
            t += (a[0][i].y-a[1][j].y)*(a[0][i].y-a[1][j].y);
            dis[1][i][j] = t;
            r = max(r, sqrt(t));
            
            t = (a[1][i].x-a[0][j].x)*(a[1][i].x-a[0][j].x);
            t += (a[1][i].y-a[0][j].y)*(a[1][i].y-a[0][j].y);
            dis[2][i][j] = t;
            r = max(r, sqrt(t));
            
            t = (a[1][i].x-a[1][j].x)*(a[1][i].x-a[1][j].x);
            t += (a[1][i].y-a[1][j].y)*(a[1][i].y-a[1][j].y);
            dis[3][i][j] = t;
            r = max(r, sqrt(t));
        }
        while(r-l > eps)
        {
            double mid = (l+r)/2;
            if(jg(mid)) l = mid;
            else r = mid;
        }
        printf("%.2f\n", l+eps);
    }
    return 0;
}
           

poj-3207 Ikki's Story IV - Panda's Trick

抽象语义,构图求解可行性。

代码:

#include <algorithm>
#include <iostream>
#include <string.h>
#include <vector>
#include <cstdio>
#include <cmath>
using namespace std;
const int maxn = 1005;
const int maxm = 4*maxn*maxn;
struct node {int u, v, next;} edge[maxm];
int no, head[maxn];
int dfn[maxn], low[maxn], index, sta[maxn], top;
bool vis[maxn];
int bel[maxn], cnt;
int n, m;
struct coordinate {int u, v;} a[maxn];
void init()
{
	no = 0;
	memset(head, -1, sizeof head);
	index = 0, top = 0;
	memset(dfn, 0, sizeof dfn);
	memset(vis, 0, sizeof vis);
	cnt = 0;
}
inline void add(int u, int v)
{
	edge[no].u = u; edge[no].v = v;
	edge[no].next = head[u]; head[u] = no++;
}
void tarjan(int u)
{
	dfn[u] = low[u] = ++index;
	sta[++top] = u, vis[u] = 1;
	for(int k = head[u]; k+1; k = edge[k].next)
	{
		int v = edge[k].v;
		if(!dfn[v])
		{
			tarjan(v);
			low[u] = min(low[u], low[v]);
		}
		else if(vis[v]) low[u] = min(low[u], dfn[v]);
	}
	if(dfn[u] == low[u])
	{
		++cnt;
		do
		{
			vis[sta[top]] = 0;
			bel[sta[top]] = cnt;
			--top;
		}
		while(sta[top+1] != u);
	}
}
bool work()
{
	for(int i = 0; i < m*2; ++i)
	if(!dfn[i]) tarjan(i);
	for(int i = 0; i < m; ++i)
	{
		if(bel[i*2] == bel[i*2+1])
		return 0;
	}
	return 1;
}
void mapping()
{
	for(int i = 0; i < m; ++i)
	{
		scanf("%d %d", &a[i].u, &a[i].v);
		if(a[i].u > a[i].v) swap(a[i].u, a[i].v);
		for(int j = 0; j < i; ++j)
		{
			if(a[i].u < a[j].u && a[i].v > a[j].u && a[i].v < a[j].v)
			add(i*2, j*2+1), add(i*2+1, j*2),
			add(j*2, i*2+1), add(j*2+1, i*2);
			if(a[j].u < a[i].u && a[j].v > a[i].u && a[j].v < a[i].v)
			add(i*2, j*2+1), add(i*2+1, j*2),
			add(j*2, i*2+1), add(j*2+1, i*2);
		}
	}
}
int main()
{
	//freopen("in.txt", "r", stdin);
	while(scanf("%d %d", &n, &m) != EOF)
	{
		init();
		mapping();
		if(work()) puts("panda is telling the truth...");
		else puts("the evil panda is lying again");
	}
	return 0;
}
           

poj-2296 Map Labeler

二分建图+可行性判断

只说一下哪几个冲突吧:同时不选,必选某点。

代码:

#include <algorithm>
#include <iostream>
#include <string.h>
#include <vector>
#include <cstdio>
using namespace std;
const int maxn = 205;
const int maxm = 4*maxn*maxn;
struct node {int u, v, next;} edge[maxm];
int no, head[maxn];
int dfn[maxn], low[maxn], _index, sta[maxn], top;
bool vis[maxn];
int bel[maxn], cnt;
int t, n;
struct coordinate {int x, y;} a[maxn];
void init()
{
	no = 0;
	memset(head, -1, sizeof head);
	_index = 0, top = 0;
	memset(dfn, 0, sizeof dfn);
	memset(vis, 0, sizeof vis);
	cnt = 0;
}
inline void add(int u, int v)
{
	edge[no].u = u; edge[no].v = v;
	edge[no].next = head[u]; head[u] = no++;
}
void tarjan(int u)
{
	dfn[u] = low[u] = ++_index;
	sta[++top] = u, vis[u] = 1;
	for(int k = head[u]; k+1; k = edge[k].next)
	{
		int v = edge[k].v;
		if(!dfn[v])
		{
			tarjan(v);
			low[u] = min(low[u], low[v]);
		}
		else if(vis[v]) low[u] = min(low[u], dfn[v]);
	}
	if(dfn[u] == low[u])
	{
		++cnt;
		do
		{
			vis[sta[top]] = 0;
			bel[sta[top]] = cnt;
			--top;
		}
		while(sta[top+1] != u);
	}
}
bool work()
{
	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])
		return 0;
	}
	return 1;
}
void mapping(int k)
{
	for(int i = 0; i < n; ++i)
	for(int j = 0; j < i; ++j)
	{
		if(abs(a[i].x-a[j].x) >= k) continue;
		if(a[i].y == a[j].y)
		add(i*2, j*2+1), add(j*2, i*2+1), add(i*2+1, j*2), add(j*2+1, i*2);
		if(a[i].y > a[j].y && a[i].y-a[j].y < k)
		add(i*2+1, i*2), add(j*2, j*2+1);
		if(a[j].y > a[i].y && a[j].y-a[i].y < k)
		add(j*2+1, j*2), add(i*2, i*2+1);
		if(a[i].y-a[j].y >= k && a[i].y-a[j].y < 2*k)
		add(i*2+1, j*2+1), add(j*2, i*2);
		if(a[j].y-a[i].y >= k && a[j].y-a[i].y < 2*k)
		add(j*2+1, i*2+1), add(i*2, j*2);
	}
}
bool jg(int k)
{
	init();
	mapping(k);
	return work();
}
int main()
{
	for(scanf("%d", &t); t--;)
	{
		scanf("%d", &n);
		for(int i = 0; i < n; ++i)
		scanf("%d %d", &a[i].x, &a[i].y);
		int l = 1, r = 20000;
		while(l <= r)
		{
			int mid = (l+r)>>1;
			if(jg(mid)) l = mid+1;
			else r = mid-1;
		}
		printf("%d\n", r);
	}
	return 0;
}
           

像刷kb菊苣的题一样也写点题外话,区域赛前2-SAT就做到这儿了,其实只要能将语义抽象出来2-SAT问题,也能抽象出所有的冲突,2-SAT就很好做了。实力还得再提高啊,路还得走...

继续加油~