[NOI2017]遊戲 題解

考慮把有11種車不適合跑這樣的條件轉化一下
11種不適合跑\longrightarrow22種適合跑,並且只能選一種車去跑
可以看到這就是一個2SAT2-SAT模板了。
考慮一下限制。
對於每場比賽拆成22個點,xx以及xx',表示這場比賽使用了哪輛適合的車
ii圖選擇hih_ijj圖選擇hjh_j
如果hih_i不適合在ii用,直接略過。
反之,如果hjh_j並不適合在jj用,那麼就讓iiii'連邊,表示這個方案並不可行。
如果都適合則連邊i,ji,ji,ji',j'
最後檢測iiii'是否在一個強聯通分量裏即可。
但是有一種圖滿足33種車都可以跑,考慮到這種圖非常少(8\leq 8 ),暴力枚舉它適合哪兩輛車即可。判定所有方案是否存在可行解即可。

#include <bits/stdc++.h>
int n,d;
int m;
int Time,top;
char s[201000];
int cn[201000];
int dfn[201000];
int low[201000];
int tck[201000];
int vis[201000];
int pos[10],C;
int scc[201000],c;
int head[201000],tot;
struct qwq{
	int p1;
	char qwp1[1];
	int use1;
	int p2;
	char qwp2[1];
	int use2;
}limit[201000];
struct edge{
	int to;
	int nxt;
}e[201000];
void add(int x,int y){
	e[++tot]={y,head[x]};
	head[x]=tot;
}
std::pair<int,int> point(int place,int use){
	if(cn[place]==1)
	  return use==2?std::make_pair(place,place+n):std::make_pair(place+n,place);
	else
	  return use==1?std::make_pair(place,place+n):std::make_pair(place+n,place);
}
void make_edge(){
  for(int i=1;i<=m;++i){
  	if(cn[limit[i].p1]==limit[i].use1)
  	  continue;
  	std::pair<int,int> fst=point(limit[i].p1,limit[i].use1);
  	if(cn[limit[i].p2]==limit[i].use2){
  	  add(fst.first,fst.second);
  	  continue;
  	}
    std::pair<int,int> scd=point(limit[i].p2,limit[i].use2);
    add(fst.first,scd.first);
    add(scd.second,fst.second);
  }
}
void tarjan(int x){
	dfn[x]=low[x]=++Time;
	tck[++top]=x;
	vis[x]=1;
	for(int i=head[x];i;i=e[i].nxt){
		int y=e[i].to;
		if(!dfn[y]){
			tarjan(y);
			low[x]=std::min(low[x],low[y]);
		}
		else
		  if(vis[y])
		    low[x]=std::min(low[x],dfn[y]);
	}
	if(dfn[x]==low[x]){
		++c;
		while(tck[top]!=x){
			vis[tck[top]]=0;
			scc[tck[top]]=c;
			--top;
		}
		vis[tck[top]]=0;
		scc[tck[top]]=c;
		--top;
	}
}
main(){
	scanf("%d%d",&n,&d);
	scanf("%s",s+1);
	scanf("%d",&m);
	for(int i=1;i<=m;++i){
	  scanf("%d%s%d%s",&limit[i].p1,limit[i].qwp1,&limit[i].p2,limit[i].qwp2);
	  limit[i].use1=limit[i].qwp1[0]-'A'+1;
	  limit[i].use2=limit[i].qwp2[0]-'A'+1;
	}
	int len=strlen(s+1);
	for(int i=1;i<=len;++i){
		if(s[i]=='a')
		  cn[i]=1;
		if(s[i]=='b')
		  cn[i]=2;
		if(s[i]=='c')
		  cn[i]=3;
		if(s[i]=='x')
		  pos[++C]=i;
	}
	for(int i=0;i<=(1<<d)-1;++i){
		tot=c=Time=top=0;
		memset(head,0,sizeof head);
	  memset(dfn,0,sizeof dfn);
	  memset(low,0,sizeof low);
	  memset(scc,0,sizeof scc);
	  memset(tck,0,sizeof tck);
	  memset(vis,0,sizeof vis);
	  for(int j=0;j<d;++j)
	    if(i&(1<<j))
	      cn[pos[j+1]]=1;
	    else
	      cn[pos[j+1]]=2;
	  make_edge();
	  for(int j=1;j<=2*n;++j)
	    if(!dfn[j])
	      tarjan(j);
	  int f=0;
	  for(int j=1;j<=n;++j)
	  	if(scc[j]==scc[j+n])
	      f=1;
	  if(!f){
	  	for(int j=1;j<=n;++j){
	  	  if(cn[j]==1)
	  	    if(scc[j]<scc[j+n])
	  	      putchar('B');
	  	    else
	  	      putchar('C');
	  	  if(cn[j]==2)
	  	    if(scc[j]<scc[j+n])
	  	      putchar('A');
	  	    else
	  	      putchar('C');
	  	  if(cn[j]==3)
	  	    if(scc[j]<scc[j+n])
	  	      putchar('A');
	  	    else
	  	      putchar('B');
	  	}
	  	return 0;
	  }
	}
	puts("-1");
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章