• LOJ#2305. 「NOI2017」游戏 枚举+2-SAT


    调都没调就 1 A 了,开心.   

    一些细节:  

    1. 当 3 个点中强制一个点不选时,又有 $(h_{i},h_{j})$ 这种限制时直接跳过即可.
    2. 当有 $(h_{i},h_{j})$ 且 $i$ 这个位置存在,但是 $j$ 不存在的时候显然是不可以选择 $i$ 的,那就直接让 $i$ 连 $i'$ 就行.
    3. 2-SAT 的建图始终是有对称性的,即 $a->b$ 就要有 $b'->a'$,这个一定注意.    

    code: 

    #include <bits/stdc++.h>     
    #define N 100009   
    #define ll long long 
    #define setIO(s) freopen(s".in","r",stdin) , freopen(s".out","w",stdout)  
    using namespace std;      
    char str[N];   
    stack<int>sta;  
    int n,D,S,m,edges,scc,tim,tot;   
    int vis[N],mark[N],bu[N],ID[2][N],ge[N][4];    
    int hd[N],to[N<<1],nex[N<<1],dfn[N],low[N],idx[N];  
    struct data 
    {
    	int i,hi,j,hj;   
    }h[N];          
    void add(int u,int v) 
    {
    	nex[++edges]=hd[u],hd[u]=edges,to[edges]=v;   
    }   
    void tarjan(int x) 
    {
    	sta.push(x),low[x]=dfn[x]=++tim;    
    	for(int i=hd[x];i;i=nex[i]) 
    	{
    		int y=to[i];  
    		if(!dfn[y]) tarjan(y),low[x]=min(low[x],low[y]);  
    		else if(!idx[y]) low[x]=min(low[x],dfn[y]);  
    	}   
    	if(low[x]==dfn[x]) 
    	{
    		++scc;  
    		for(;;) 
    		{
    			int u=sta.top(); sta.pop();   
    			idx[u]=scc;   
    			if(u==x) break;  
    		}
    	}
    }      
    void clr() 
    {
    	for(int i=1;i<=tot;++i) hd[i]=dfn[i]=low[i]=idx[i]=0;   
    	for(int i=0;i<=edges;++i)  nex[i]=to[i]=0;   
    } 
    int calc() 
    {       
    	int x,y,z;               
    	for(int i=1;i<=n;++i)  
    	{
    		if(vis[i]) 
    		{
    			if(mark[i]==0) str[i]='a';        
    			if(mark[i]==1) str[i]='b';  
    		}
    		if(str[i]=='a') ge[i][1]=0,ge[i][2]=1;          
    		if(str[i]=='b') ge[i][0]=0,ge[i][2]=1;   
    		if(str[i]=='c') ge[i][0]=0,ge[i][1]=1;   
    	}
    	for(int i=1;i<=m;++i) 
    	{
    		data e=h[i];        
    		// 反正肯定不会选         
    		if(str[e.i]=='a'+e.hi) continue;          
    		// 当前肯定不能选 
    		if(str[e.j]=='a'+e.hj) 
    		{   
    			add(ID[ge[e.i][e.hi]][e.i],ID[ge[e.i][e.hi]^1][e.i]);    
    			continue;   
    		}    
    		// i->j, j'->i'    
    		add(ID[ge[e.i][e.hi]][e.i],ID[ge[e.j][e.hj]][e.j]);   
    		add(ID[ge[e.j][e.hj]^1][e.j],ID[ge[e.i][e.hi]^1][e.i]);
     	}         
    	for(int i=1;i<=tot;++i)  if(!dfn[i])   tarjan(i);      
    	int flag=1;   
    	for(int i=1;i<=n;++i) if(idx[ID[0][i]]==idx[ID[1][i]]) flag=0;             
    	if(flag) 
    	{ 
    		for(int i=1;i<=n;++i) 
    		{
    			x=ID[0][i],y=ID[1][i];          
    			if(str[i]=='a') printf("%c",idx[x]<idx[y]?'B':'C');  
    			if(str[i]=='b') printf("%c",idx[x]<idx[y]?'A':'C');   
    			if(str[i]=='c') printf("%c",idx[x]<idx[y]?'A':'B');   
    		}
    	}   
    	clr();   
    	return flag;    
    }    
    int main() 
    { 
    	// setIO("input");         
    	int x,y,z; 
    	char a[2],b[2];  
    	scanf("%d%d%s%d",&n,&x,str+1,&m);                 
    	for(int i=1;i<=m;++i)   
    	{   
    		scanf("%d%s%d%s",&h[i].i,a,&h[i].j,b);  
    		h[i].hi=a[0]-'A',h[i].hj=b[0]-'A';    
    	} 
    	for(int i=1;i<=n;++i)  if(str[i]=='x') vis[i]=1,bu[++D]=i;    
    	for(int i=1;i<=n;++i)  ID[0][i]=++tot;  
    	for(int i=1;i<=n;++i)  ID[1][i]=++tot;            
    	// 0 表示 不选 A 
    	// 1 表示 不选 B        
    	for(int i=0;i<(1<<D);++i)      
    	{
    		for(int j=0;j<D;++j)  
    		{
    			if(i&(1<<j)) mark[bu[j+1]]=1; 
    			else mark[bu[j+1]]=0;          
    		}
    		if(calc())  return 0;  
    	}          
    	if(!D&&calc())  return 0;    
    	printf("-1"); 
    	return 0; 
    }
    

      

  • 相关阅读:
    (一二二)核心动画进阶
    1089. Insert or Merge (25)
    (一二一)核心动画基础
    (一二〇)CALayer的一些特性
    (一一九)通过CALayer实现阴影、圆角、边框和3D变换
    1086. Tree Traversals Again (25)
    POJ 2610:Dog & Gopher
    模拟内存分配(链表实现)
    圣诞树后能找到我的记忆
    YTU 2797: 复仇者联盟之关灯
  • 原文地址:https://www.cnblogs.com/guangheli/p/13072957.html
Copyright © 2020-2023  润新知