PO 3683 2-sat问题

白皮书上的例题,记录一下模板。
学习一下判断两个区间是否重叠的办法,当且仅当,左端点的最大值小于右端点的最小值的时候,有交集。(具体问题分析取等号的问题)
当然直接向我这样调用函数判断,没有交集的情况也是可以的,不过慢了300ms。。。。所以还是用白皮书的方法好。
这里留一个坑,不太明白为什么最后拓扑排序,大于自己的反就是true,小于就是false。
2-sat问题指的是,析取范式中,每个括号只有两个变量的时候的值。
其实还是很好理解的。
比如~x∨y代表 ~x或者y选一个为真,另一个为假,为什么只能选一个呢?按照真值表,析取不该是11的时候也等于1么?
我们先做等价变化,(离散学的变换名字是啥忘记了。。),~x∨y= x->y && ~y-> ~x(其实就是,两个析取的值,等价于,一个取反推另一个)。
我们将->表示成有向边,我们给x,y建立边了,给~y ~x建立边了,对于2-sat问题我们跑scc(强连通分量,因为可以知道,如果图里面连城了一个圈,那么这个圈的值就是圈里面每一个值,即,圈里面每一个元素的真值是一样的),所以只要x ~x等等(即自己和自己的反)不在一个圈里面,那么问题就是有解的。
所以回过来,如果两个都取1,那么对于他们的反来说都是0,所以就会存在圈的值为零,我们这里是要寻找的是,让所有圈变成1(因为我们做的是真值表,对于&&可以理解成,有向图对于每一个圈连一条边,从头开始跑到尾,都要为真,因为1&&1才等于1)所以这样就是错误的了。
回到这道题的解放上来,我们理解边的指向的意思为:选a必选b。(a->b)
那么就可以理解,~a拓扑在前,会出现 ~a->(a所在的块),即选 ~a必选a,这是错误的
所以这里我们就只能选择a了,如果a在前,选a必选~a,那么我们就只能选 ~a了。
所以最后的解。。看天意。。看拓扑究竟是怎么样的,先来后到。。(大自然所谓的公平)

#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
typedef pair<int, int> pir;
int n;
struct {
	int s, t, d;
}hm[1005];
bool used[2005];
int cmp[2005];
//int color[2005];
vector<int >vs;
vector<int >sc[2005];
vector<int >g[2005];
vector<int >r[2005];
bool judge(int s1, int e1, int s2, int e2)
{
//	cout << "s1 " << s1 << "e1 " << e1 << "s2 " << s2 << "e2 " << e2 << endl;
//	cout<<!((s1 >= e2) || (s2 >= e1));
	if ((s1 >= e2) || (s2 >=e1))return 0;
	else return 1;
	
}//这么写慢了啊
void addedge(int f, int s)
{
	g[f].push_back(s);
	r[s].push_back(f);
}
void dfs(int v)
{
	used[v] = true;
	up(i, 0, g[v].size())
		if (!used[g[v][i]])dfs(g[v][i]);
	vs.push_back(v);
}
void rdfs(int v, int k)
{
	used[v] = true;
	cmp[v] = k;
	sc[k].push_back(v);
	up(i, 0, r[v].size())
		if (!used[r[v][i]])rdfs(r[v][i], k);
}
int scc()
{
	memset(used, 0, sizeof(used));
	vs.clear();
	int N = 2 * n;
	up(i, 0, N)
		if (!used[i])dfs(i);
	memset(used, 0, sizeof(used));
	int k = 0;
	dwd(i,vs.size()-1,0)
		if (!used[vs[i]])rdfs(vs[i], k++);
	up(i, 0, n)
	{
		//cout<<cmp[i]<<cmp[i+n];
		if (cmp[i] == cmp[i + n])
			return -1;
	}	
	return k;
}//scc模板,套用就行了
int main()
{
	cin >> n;
	int x, y,a,b,c;
	up(i, 0, n)
	{
		scanf("%d:%d %d:%d %d", &x, &y,&a,&b,&c);
		hm[i].s = x * 60 + y;
		hm[i].t = a * 60 + b;
		hm[i].d = c;
		//cout << hm[i].s << hm[i].t << hm[i].d << endl;
	}
	up(i, 0, n)
	{
		up(j, 0, n)
		{
			if (i == j)continue;
			if (judge(hm[i].s,hm[i].s+hm[i].d,hm[j].s,hm[j].s+hm[j].d))
			{
				//cout << "1*  " << i << j << endl;
				addedge(i, n + j);
				addedge(j, n + i);
			}
			if (judge(hm[i].s,hm[i].s+hm[i].d,hm[j].t-hm[j].d,hm[j].t))
			{
//				cout << "2*  " << i << j << endl;

				addedge(i,j);
				addedge(j+n, i+n);
			}
			if (judge(hm[i].t-hm[i].d,hm[i].t,hm[j].s,hm[j].s+hm[j].d))
			{
			//	cout << "3*  " << i << j << endl;
				//cout << judge(hm[i].t - hm[i].d, hm[i].t, hm[j].s, hm[j].s + hm[i].d);
				addedge(i + n, j + n);
				addedge(j,i);
			}
			if (judge(hm[i].t-hm[i].d,hm[i].t,hm[j].t-hm[j].d,hm[j].t))
			{
				//cout << "4*  " << i << j << endl;

				addedge(i + n, j);
				addedge(j + n, i);
			}
		}
	}
	int temp=scc();
	if (temp == -1) { cout << "NO" << endl; return 0; }
	else cout << "YES" << endl;
	//up(i, 0, temp)
	//{
	//	up(j, 0, sc[i].size())
	//	{
	//		if (color[sc[i][j]] == 0)
	//		{
	//			color[sc[i][j]] == 1;
	//			if (sc[i][j] >= n)
	//			{
	//				color[sc[i][j] - n] = 2;
	//			}
	//			else color[sc[i][j] + n] = 2;
	//		}
	//	}
	//}//这里本来想尝试染色的,不过后来发现直接用拓扑就好了。
	up(i, 0, n)
	{
	//	cout << cmp[i] << cmp[i + n] << endl;
		if (cmp[i]>cmp[i+n])
		{
			printf("%02d:%02d %02d:%02d\n", hm[i].s / 60, hm[i].s % 60, (hm[i].s+hm[i].d)/60,(hm[i].s+hm[i].d)%60);
		}
		else
		{
			printf("%02d:%02d %02d:%02d\n", (hm[i].t - hm[i].d) / 60, (hm[i].t - hm[i].d) % 60, hm[i].t / 60, hm[i].t % 60);
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_44019404/article/details/89386578
今日推荐