POJ 2723 解题报告

这道题是我做的第3道2SAT问题。还是没有完全理解,但是更清楚了些。这道题仍然只是判断2SAT是否有界,不需要求解。

这里我把每个钥匙看做2SAT里面的一个元素,即一共2M个,考虑到true和false,即xi和~xi,一共4M个。每对不能同时取,即取xi的时候,必须取~xj.另外一个限制是对门的个数二分查找,即考虑前mid个门。每个门,两把钥匙不能同时不取,即取~xi的时候,必须取xj。

这应该是最简单直观(但是不高效)的做法了。同时实现也需要优化(从而避免重复动态分配空间)。但是过了就不考虑了。。。

看到了这个对2SAT最通俗的解释:

http://blog.csdn.net/jarjingx/article/details/8521690


thestoryofsnow2723Accepted724K1829MSC++4385B

/* 
ID: thestor1 
LANG: C++ 
TASK: poj2723 
*/
#include <iostream>
#include <fstream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <limits>
#include <string>
#include <vector>
#include <list>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <algorithm>
#include <cassert>

using namespace std;

const int MAXN = 1024;
const int MAXM = 2048;

vector<int> indexes(2 * MAXM, -1);
vector<int> lowlinks(2 * MAXM, -1);
vector<bool> onStack(2 * MAXM, false);

bool isundefined(int u, vector<int> &indexes)
{
	return indexes[u] < 0;
}

void strongconnect(int u, int &index, int &SCCNO, vector<int> &sccnos, stack<int> &S, const vector<vector<int> > &adjs, const int N)
{
	// Set the depth index for u to the smallest unused index
	indexes[u] = index;
	lowlinks[u] = index;
	index++;

	S.push(u);
	onStack[u] = true;

	 // Consider successors of u
	for (int i = 0; i < adjs[u].size(); ++i)
	{
		int v = adjs[u][i];

		if (isundefined(v, indexes))
		{
			// Successor v has not yet been visited; recurse on it
			strongconnect(v, index, SCCNO, sccnos, S, adjs, N);
			lowlinks[u] = min(lowlinks[u], lowlinks[v]);
		}
		else if (onStack[v])
		{
			// Successor v is in stack S and hence in the current SCC
			lowlinks[u] = min(lowlinks[u], lowlinks[v]);	
		}
	}

	// If u is a root node, pop the stack and generate an SCC
	if (indexes[u] == lowlinks[u])
	{
		// start a new strongly connected component
		while (true)
		{
			int v = S.top();
			S.pop();
			onStack[v] = false;

			// add v to current strongly connected component
			sccnos[v] = SCCNO;

			if (v == u)
			{
				break;
			}
		}

		SCCNO++;
	}
}

// Tarjan's strongly connected components algorithm
// See http://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
void tarjan(const vector<vector<int> > &adjs, int &SCCNO, vector<int> &sccnos, const int N)
{
	int index = 0;
	// vector<int> indexes(N, -1);
	for (int i = 0; i < N; ++i)
	{
		indexes[i] = -1;
	}
	// vector<int> lowlinks(N, -1);
	for (int i = 0; i < N; ++i)
	{
		lowlinks[i] = -1;
	}

	stack<int> S;
	// vector<bool> onStack(N, false);
	for (int i = 0; i < N; ++i)
	{
		onStack[i] = false;
	}
	
	for (int u = 0; u < N; ++u)
	{
		if (isundefined(u, indexes))
		{
			strongconnect(u, index, SCCNO, sccnos, S, adjs, N);
		}
	}
}

int main()
{
	int opposite[2 * MAXN];
	int doors[2 * MAXM][2];
	vector<int> sccnos(2 * MAXM, -1);

	int N, M;
	int k1, k2;
	while (scanf("%d%d", &N, &M) > 0)
	{
		// printf("[debug]N: %d, M: %d\n", N, M);
		// no more test cases
		if (N == 0 && M == 0)
		{
			break;
		}

		for (int i = 0; i < N; ++i)
		{
			scanf("%d%d", &k1, &k2);
			opposite[k1] = k2;
			opposite[k2] = k1;
		}

		for (int i = 0; i < M; ++i)
		{
			scanf("%d%d", &doors[i][0], &doors[i][1]);
		}

		int left = 0, right = M - 1, mid;
		while (left <= right)
		{
			mid = (left + right) / 2;
			
			// At most one can be chosen from {i, opposite[i]}
			vector<vector<int> > adjs(N * 2 * 2, std::vector<int>());
			for (int i = 0; i < 2 * N; ++i)
			{
				// i, opposite[i] cannot both be true
				adjs[i].push_back(opposite[i] + 2 * N);
				adjs[opposite[i]].push_back(i + 2 * N);
			}

			for (int i = 0; i <= mid; ++i)
			{
				// doors[i][0], doors[i][1] cannot both be false (have to choose one of them)
				adjs[doors[i][0] + 2 * N].push_back(doors[i][1]);
				adjs[doors[i][1] + 2 * N].push_back(doors[i][0]);
			}

			// printf("[debug]adjs:\n");
			// for (int i = 0; i < 2 * M; ++i)
			// {
			// 	printf("%d: ", i);
			// 	for (int j = 0; j < adjs[i].size(); ++j)
			// 	{
			// 		printf("%d ", adjs[i][j]);
			// 	}
			// 	printf("\n");
			// }


			int SCCNO = 0;
			for (int i = 0; i < 2 * N; ++i)
			{
				sccnos[i] = -1;
				sccnos[i + 2 * N] = -1;
			}
			tarjan(adjs, SCCNO, sccnos, 4 * N);

			// printf("[debug]sccnos[%d]:\n", SCCNO);
			// for (int i = 0; i < mid; ++i)
			// {
			// 	printf("%d: %d\n", i, sccnos[i]);
			// 	printf("%d: %d\n", i + M, sccnos[i + M]);
			// }

			bool conflict = false;
			for (int i = 0; i < 2 * N; ++i)
			{
				// if both x and ~x are true, we have conflicts here
				if (sccnos[i] == sccnos[i + 2 * N])
				{
					conflict = true;
					break;
				}
			}

			// printf("[debug]mid: %d, conflict: %d\n", mid, conflict);
			if (conflict)
			{
				right = mid - 1;
			}
			else
			{
				left = mid + 1;
			}
		}

		printf("%d\n", left);
	}

	return 0;  
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值