LA 3713 Astronauts 2-SAT问题

LA 3713

题意:有A,B,C三个任务分给n个宇航员,每个宇航员恰好分配一个任务,要求宇航员年龄大于等于平均年龄可以分配A,小于平均年龄可以分配B,C任务无要求,给出m对相互讨厌的宇航员,相互讨厌的宇航员不能分配相同任务,求满足所有要求的任务分配方案。

思路:年龄大于等于平均年龄只能做A或C,小于的只能做B或C,假设做任务A,B是true,做任务C是false,那么一对相互讨厌的人 i 和 j 如果他们年龄是同类型,可以得到两个逻辑句 xi V xj 和 非xi V 非xj,如果年龄不同类型,只有xi V xj,接下来就转化成2-SAT模板题了。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn=1e5+2;
int n,a[maxn];
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 main()
{
	int m,i,u,v;
	while(~scanf("%d%d",&n,&m)&&n&&m)
	{
		int sum=0;
		solver.init(n);
		for(i=0;i<n;i++)
		{
			scanf("%d",&a[i]);
			sum+=a[i];
		}
		for(i=0;i<m;i++)
		{
			scanf("%d%d",&u,&v);u--;v--;
			int t1=max(a[u],a[v]);
			int t2=min(a[u],a[v]);
			if(t2*n>=sum||t1*n<sum)
			{
				solver.add_clause(u,1,v,1);
				solver.add_clause(u,0,v,0);
			}
			else
			solver.add_clause(u,1,v,1);
		}
		if(!solver.solve())
		printf("No solution.\n");
		else
		{
			for(int i=0;i<n;i++)
			if(solver.mark[i*2+1])
			{
				if(a[i]*n>=sum)
				printf("A\n");
				else
				printf("B\n");
			}
			else
			printf("C\n");
		}
	}
}

猜你喜欢

转载自blog.csdn.net/ccsu_cat/article/details/80867696
LA
今日推荐