LA 3211 Now or later 2-SAT问题

LA 3211

题意:有n架飞机要着陆,每个飞机有两个可选择的着陆时间点,把每个飞机的着陆时间排序,求相邻两个飞机的着陆时间间隔的最小值应尽量大。

思路:最小值最大,用二分解决,用二分查询答案ans,每次检查的时候可以构造2-SAT问题,先遍历n*(n-1)个飞机找到两个飞机着陆时间间隔小于ans,假设飞机 i 的第 a 个着陆时间与飞机 j 的第 b 的着陆时间相差小于 ans ,可以将 i*2+a连接j*2+b^1,将j*2+b连接i*2+a^1,因此构造了2-SAT问题就可套模板了。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn=2e3+2;
int n,T[maxn][2];
struct TwoSAT{
	int n;
	vector<int>G[maxn*2];
	bool mark[maxn*2];
	int S[maxn*2],c;
	
	bool dfs(int x){
		if(mark[x^1])return false;
		if(mark[x])return true;
		mark[x]=true;
		S[c++]=x;
		for(int i=0;i<G[x].size();i++)
		if(!dfs(G[x][i]))
		return false;
		return true;
	} 
	
	void init(int n)
	{
		this->n=n;
		for(int i=0;i<n*2;i++)G[i].clear();
		memset(mark,0,sizeof(mark));
	}
	
	void add_clause(int x,int xval,int y,int yval){
		x=x*2+xval;
		y=y*2+yval;
		G[x^1].push_back(y);
		G[y^1].push_back(x);
	}
	
	bool solve()
	{
		for(int i=0;i<n*2;i+=2)
		if(!mark[i]&&!mark[i+1])
		{
			c=0;
			if(!dfs(i))
			{
				while(c)
				mark[S[--c]]=false;
				if(!dfs(i+1))
				return false;
			}
		}
		return true;
	}
}solver;
int test(int diff)
{
	solver.init(n);
	for(int i=0;i<n;i++)for(int a=0;a<2;a++)
	for(int j=i+1;j<n;j++)for(int b=0;b<2;b++)
	if(abs(T[i][a]-T[j][b])<diff)
	solver.add_clause(i,a^1,j,b^1);
	return solver.solve();
}
int main()
{
	while(~scanf("%d",&n))
	{
		int M,L=0,R=0;
		for(int i=0;i<n;i++)
		for(int a=0;a<2;a++)
		{
			scanf("%d",&T[i][a]);
			R=max(R,T[i][a]);
		}
		R++;
		while(L<R)
		{
			M=(L+R)/2;
			if(test(M))
			{
				if(L==M)
				break;
				L=M;
			}
			else
			R=M;
		}
		printf("%d\n",M);
	}
}

猜你喜欢

转载自blog.csdn.net/ccsu_cat/article/details/80807079
LA
now