zoukankan      html  css  js  c++  java
  • 【XSY2750】Mythological V 2-sat

    题目描述

      有一棵(n)个点的树,还有(m)个物品。

      你要把每个物品放在树上的一个点上(两个物品可以放在同一个点)。

      有(q)个限制:(a,b)两个物品在路上的最短路经过(c)

      要你构造一组合法的方案。

      (n,mleq 250)

    题解

      很容易想到2-sat。

      但是把点看成"物品(x)放在(y)上"会找不到合法解。

      所以要把点看成“物品(x)在以(y)为根的子树内”,这样根就是必须选的。

      连边的话(下面只列出一半的边):(x ightarrow f_x,x ightarrow !y)((y)(x)的兄弟)(这些边可以弄一些前缀后缀的点优化)

      和询问有关的:

      1.(a eq b)((a,x) ightarrow !(b,x))((x)(c)的儿子),(!(a,c) ightarrow (b,c))

      2.(a=b)(!(a,c) ightarrow(a,c)),((a,x) ightarrow !(a,x))((x)(c)的儿子)。

      点数为(O(nm))

      边数为(O(nm^2))

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    using namespace std;
    struct graph
    {
    	int h[400010];
    	int v[40000010];
    	int t[40000010];
    	int n;
    	graph()
    	{
    		n=0;
    		memset(h,0,sizeof h);
    	}
    	void add(int x,int y)
    	{
    		n++;
    		v[n]=y;
    		t[n]=h[x];
    		h[x]=n;
    	}
    };
    graph g;
    vector<int> t[260],t2;
    int n,m,q;
    int id(int x,int y)//x=物品,y=点
    {
    	return (y-1)*m+x;
    }
    int cnt;
    int pre[260],suf[260];
    void add0(int k1,int x,int k2,int y)
    {
    	g.add(id(k1,x)*2-1,id(k2,y)*2);
    	g.add(id(k2,y)*2-1,id(k1,x)*2);
    }
    void add4(int k1,int x,int k2,int y)
    {
    	g.add(id(k1,x)*2,id(k2,y)*2-1);
    	g.add(id(k2,y)*2,id(k1,x)*2-1);
    }
    void add1(int k1,int x,int k2,int y)
    {
    	g.add(id(k1,x)*2-1,id(k2,y)*2-1);
    	g.add(id(k2,y)*2,id(k1,x)*2);
    }
    void add2(int k,int x)
    {
    	g.add(id(k,x)*2,id(k,x)*2-1);
    }
    void add3(int k,int x)
    {
    	g.add(id(k,x)*2-1,id(k,x)*2);
    }
    int f[300];
    int d[300];
    void dfs(int x,int fa,int dep)
    {
    	t2.clear();
    	f[x]=fa;
    	d[x]=dep;
    	for(auto v:t[x])
    		if(v!=fa)
    			t2.push_back(v);
    	t[x]=t2;
    	for(auto v:t[x])
    		dfs(v,x,dep+1);
    }
    int b[400010];
    int e[400010];
    int ti,tot,top;
    int st[400010];
    int dfn[400010];
    int low[400010];
    int c[300][300][300];
    void dfs(int x)
    {
    	low[x]=dfn[x]=++ti;
    	st[++top]=x;
    	b[x]=1;
    	for(int i=g.h[x];i;i=g.t[i])
    	{
    		if(b[g.v[i]]!=2)
    		{
    			if(!b[g.v[i]])
    				dfs(g.v[i]);
    			low[x]=min(low[x],low[g.v[i]]);
    		}
    	}
    	if(low[x]>=dfn[x])
    	{
    		int v;
    		tot++;
    		do
    		{
    			v=st[top--];
    			e[v]=tot;
    			b[v]=2;
    		}
    		while(v!=x);
    	}
    }
    int main()
    {
    #ifndef ONLINE_JUDGE
    	freopen("a.in","r",stdin);
    	freopen("a.out","w",stdout);
    #endif
    	scanf("%d%d%d",&n,&m,&q);
    	int x,y,z;
    	for(int i=1;i<n;i++)
    	{
    		scanf("%d%d",&x,&y);
    		t[x].push_back(y);
    		t[y].push_back(x);
    	}
    	dfs(1,0,1);
    	cnt=n;
    	for(int i=1;i<=n;i++)
    	{
    		if(i!=1)
    			for(int k=1;k<=m;k++)
    				add1(k,i,k,f[i]);
    		int sz=t[i].size();
    		for(int j=0;j<sz;j++)
    		{
    			pre[j]=++cnt;
    			for(int k=1;k<=m;k++)
    				add1(k,t[i][j],k,pre[j]);
    			if(j)
    				for(int k=1;k<=m;k++)
    					add1(k,pre[j-1],k,pre[j]);
    		}
    		for(int j=sz-1;j>=0;j--)
    		{
    			suf[j]=++cnt;
    			for(int k=1;k<=m;k++)
    				add1(k,t[i][j],k,suf[j]);
    			if(j!=sz-1)
    				for(int k=1;k<=m;k++)
    					add1(k,suf[j+1],k,suf[j]);
    		}
    		for(int j=0;j<sz;j++)
    		{
    			if(j)
    				for(int k=1;k<=m;k++)
    					add0(k,t[i][j],k,pre[j-1]);
    			if(j!=sz-1)
    				for(int k=1;k<=m;k++)
    					add0(k,t[i][j],k,suf[j+1]);
    		}
    	}
    	for(int i=1;i<=m;i++)
    		add2(i,1);
    	memset(b,0,sizeof b);
    	for(int i=1;i<=q;i++)
    	{
    		scanf("%d%d%d",&x,&y,&z);
    		if(x>y)
    			swap(x,y);
    		if(c[x][y][z])
    			continue;
    		c[x][y][z]=1;
    		if(x==y)
    		{
    			add2(x,z);
    			for(auto v:t[z])
    				add3(x,v);
    		}
    		else
    		{
    			for(auto v:t[z])
    				add0(x,v,y,v);
    			add4(x,z,y,z);
    		}
    	}
    	ti=0;
    	tot=0;
    	top=0;
    	for(int i=1;i<=2*m*cnt;i++)
    		if(!b[i])
    			dfs(i);
    	for(int i=1;i<=m;i++)
    	{
    		int ans=1;
    		for(int j=1;j<=n;j++)
    			if(e[2*id(i,j)-1]<e[2*id(i,j)])
    				if(d[j]>d[ans])
    					ans=j;
    		printf("%d ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    使用duilib链接错误 _declspec(dllimport)
    USB磁盘VID和PID 对应到次盘盘符相关文章
    路径拆分函数
    COM问题
    将对话框嵌入父窗体
    duilib的caption上的Edit无法激活
    LoadLibrary失败,GetLastError MOD_NOT_FOUND
    windows字符串
    windows界面库种类
    windows插件框架
  • 原文地址:https://www.cnblogs.com/ywwyww/p/8599008.html
Copyright © 2011-2022 走看看