[JSOI2010] 滿漢全席
阿新 • • 發佈:2018-10-25
turn 滿漢全席 pro 選擇 class tar names cstring .org
洛谷 P4171 傳送門
bzoj1823 傳送門
2-SAT裸題。
簡單講一下2-SAT:
首先把題目給出的種種限制轉換為一個圖。
以這道題來說,每種菜看作是兩個點,一個點代表做成漢式,另一個代表做成滿式。
然後考慮約束條件:
比如:評委要求A做成漢式,B做成滿式。
那麽如果A做成滿式,B就一定是滿式;同理,如果B做成漢式,那A一定是漢式。
所以這麽連邊:A滿-->B滿、B漢->A漢。
不同的題連邊方法也略有不同。
然後對這個圖求一個強連通分量。
顯然,如果選擇了某個點,那麽那個點所在的強連通分量裏的所有點都要選擇。
對於1<=X<=n:
如果存在某個X,X漢和X滿在一個強連通分量裏,就無解。
否則有解。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 6 int k; 7 int n,m; 8 int hd[205],to[2005],nx[2005],ec; 9 10 int dish(int id,int kd) 11 { 12 return id*2-kd; 13 } 14 15 void edge(int af,int at) 16 { 17 to[++ec]=at;18 nx[ec]=hd[af]; 19 hd[af]=ec; 20 } 21 22 int dfn[205],low[205],dc; 23 int in[205],st[205],tp; 24 int gr[205],gsz[205],gc; 25 26 void tarjan(int p) 27 { 28 dfn[p]=low[p]=++dc; 29 st[++tp]=p; 30 in[p]=1; 31 for(int i=hd[p];i;i=nx[i]) 32 { 33 if(!dfn[to[i]])tarjan(to[i]),low[p]=min(low[p],low[to[i]]);34 else if(in[to[i]])low[p]=min(low[p],dfn[to[i]]); 35 } 36 if(low[p]==dfn[p]) 37 { 38 gc++; 39 int np=0; 40 while(np!=p) 41 { 42 np=st[tp--]; 43 gr[np]=gc; 44 gsz[gc]++; 45 in[np]=0; 46 } 47 } 48 } 49 50 void clean() 51 { 52 memset(hd,0,sizeof(hd)); 53 memset(dfn,0,sizeof(dfn)); 54 memset(low,0,sizeof(low)); 55 memset(gsz,0,sizeof(gsz)); 56 dc=ec=gc=0; 57 } 58 59 int main() 60 { 61 scanf("%d",&k); 62 while(k--) 63 { 64 clean(); 65 scanf("%d%d",&n,&m); 66 for(int i=1;i<=m;i++) 67 { 68 int id[2]={0,0},kd[2],p; 69 char lim[10]; 70 for(int j=0;j<=1;j++) 71 { 72 scanf("%s",lim+1); 73 p=1; 74 kd[j]=(lim[p++]==‘m‘); 75 while(lim[p]>=‘0‘&&lim[p]<=‘9‘) 76 id[j]=id[j]*10+lim[p++]-‘0‘; 77 } 78 edge(dish(id[0],kd[0]^1),dish(id[1],kd[1])); 79 edge(dish(id[1],kd[1]^1),dish(id[0],kd[0])); 80 } 81 for(int i=1;i<=2*n;i++) 82 if(!dfn[i])tarjan(i); 83 int fl=1; 84 for(int i=1;i<=n;i++) 85 { 86 if(gr[dish(i,0)]==gr[dish(i,1)]) 87 { 88 fl=0; 89 break; 90 } 91 } 92 if(fl)printf("GOOD\n"); 93 else printf("BAD\n"); 94 } 95 return 0; 96 }
[JSOI2010] 滿漢全席