• [NOI2017] 游戏


    X.[NOI2017] 游戏

    因为并没有专门开2SAT笔记,所以就放这了

    好久没用2SAT了,都忘光了……

    首先,我们可以 (2^d) 枚举所有 x 型赛道是当 a 型用还是当 b 型用,因为 a 型允许你选 BC,而 b 型又允许你选 A,这样就涵盖了全部情形。

    这样之后,我们便考虑建立2SAT模型。

    对于一组限制 ((u,v)),若 (u) 选择的颜色是被禁止的颜色,显然可以不予考虑;若 (v) 选择的颜色是被禁止的颜色,显然这会使得选 (u) 不合法;怎么让选 (u) 不合法呢?连边 ((u,u')) 即可。

    否则,其就是一条常规的限制,连边 ((u,v)),同时也别忘记连边 ((v',u')),因为若 (v) 没有选择强制它选择的颜色,则 (u) 也一定不能选择具有强制效力的颜色。

    于是直接Tarjan跑2SAT即可。时间复杂度 (OBig((n+m)2^dBig))

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    int a[3][3]={{-1,0,1},{0,-1,1},{0,1,-1}},b[3][2]={{1,2},{0,2},{0,1}};
    int n,d,m,tp[50010];
    char str[50010];
    struct EDGE{
    	int u,v,cu,cv;
    	EDGE(){}
    	EDGE(int U,int V,int CU,int CV){u=U,v=V,cu=CU,cv=CV;}
    }e[100100];
    vector<int>v[100010],u;
    int dfn[100010],low[100010],tot,col[100010],c;
    stack<int>s;
    void Tarjan(int x){
    	dfn[x]=low[x]=++tot,s.push(x);
    	for(auto y:v[x]){
    		if(!dfn[y])Tarjan(y),low[x]=min(low[x],low[y]);
    		else if(!col[y])low[x]=min(low[x],dfn[y]); 
    	}
    	if(dfn[x]>low[x])return;
    	c++;
    	while(s.top()!=x)col[s.top()]=c,s.pop();
    	col[s.top()]=c,s.pop();
    }
    bool che(){
    	tot=c=0;for(int i=1;i<=2*n;i++)dfn[i]=low[i]=col[i]=0,v[i].clear();
    	for(int i=1;i<=m;i++){
    		int X=a[tp[e[i].u]][e[i].cu],Y=a[tp[e[i].v]][e[i].cv];
    //		printf("%d %d
    ",X,Y);
    		if(e[i].cu==tp[e[i].u])continue;
    		if(e[i].cv==tp[e[i].v])v[X*n+e[i].u].push_back((!X)*n+e[i].u);else v[X*n+e[i].u].push_back(Y*n+e[i].v),v[(!Y)*n+e[i].v].push_back((!X)*n+e[i].u);
    	}
    	for(int i=1;i<=2*n;i++)if(!dfn[i])Tarjan(i);
    	for(int i=1;i<=n;i++)if(col[i]==col[i+n])return false;
    	for(int i=1;i<=n;i++)putchar('A'+b[tp[i]][(col[i]>col[i+n])]);putchar('
    ');
    	return true;
    }
    int main(){
    	scanf("%d%d",&n,&d);
    	scanf("%s",str+1);
    	for(int i=1;i<=n;i++)if(str[i]=='x')u.push_back(i);else tp[i]=str[i]-'a';
    	scanf("%d",&m);
    	for(int i=1,x,y;i<=m;i++)scanf("%d%s%d%s",&x,str,&y,str+10),e[i]=EDGE(x,y,str[0]-'A',str[10]-'A');
    	for(int i=0;i<(1<<u.size());i++){
    		for(int j=0;j<u.size();j++)tp[u[j]]=(i>>j)&1;
    		if(che())return 0;
    	}
    	puts("-1");
    	return 0;
    }
    

  • 相关阅读:
    12345679*81=?
    怪异,漂亮的几个数学恒等式(转)
    道路着色问题
    一组数学算式的欣赏(转)
    数学中奇妙的“金蝉脱壳”(转)
    数学中的分分合合(转)
    四方定理和卡布列克常数(转)
    简单的题目 有趣的现象
    Android学习笔记 第三节 基本控件学习
    Android学习笔记 第二节 HelloWorld程序
  • 原文地址:https://www.cnblogs.com/Troverld/p/14621887.html
Copyright © 2020-2023  润新知