P3825 [NOI2017]游戏
?
P3825 [NOI2017]游戲
?
題目描述
小 L 計劃進行n場游戲,每場游戲使用一張地圖,小 L 會選擇一輛車在該地圖上完成游戲。
小 L 的賽車有三輛,分別用大寫字母A、B、C表示。地圖一共有四種,分別用小寫字母x、a、b、c表示。其中,賽車A不適合在地圖a上使用,賽車B不適合在地圖b上使用,賽車C不適合在地圖c上使用,而地圖x則適合所有賽車參加。適合所有賽車參加的地圖并不多見,最多只會有d張。
n場游戲的地圖可以用一個小寫字母組成的字符串描述。例如:S=xaabxcbc?表示小 L 計劃進行8場游戲,其中第1場和第5場的地圖類型是x,適合所有賽車,第2場和第3場的地圖是a,不適合賽車A,第44場和第77場的地圖是b,不適合賽車B,第6場和第88場的地圖是c,不適合賽車C。
小 L 對游戲有一些特殊的要求,這些要求可以用四元組??? 來描述,表示若在第ii場使用型號為???的車子,則第j場游戲要使用型號為???的車子。
你能幫小 L 選擇每場游戲使用的賽車嗎?如果有多種方案,輸出任意一種方案。如果無解,輸出 “-1’’(不含雙引號)。
輸入格式
輸入第一行包含兩個非負整數n, d。
輸入第二行為一個字符串S。n, d, S的含義見題目描述,其中S包含n個字符,且其中恰好d個為小寫字母x。
輸入第三行為一個正整數m,表示有m條用車規則。接下來m行,每行包含一個四元組??? ,其中i, j為整數,, ?為字符a、b或c,含義見題目描述。
輸出格式
輸出一行。
若無解輸出 “-1’’(不含雙引號)。
若有解,則包含一個長度為n的僅包含大寫字母A、B、C的字符串,表示小 L 在這n場游戲中如何安排賽車的使用。如果存在多組解,輸出其中任意一組即可。
數據范圍
?
Solution
感覺2-SAT的題都比較顯然吧,只要是每組二選一的大多都可以2-SAT。
先從整體觀察此題。題意是給每個位置從ABC三種字母中選擇一個填入,某些位置只有兩個選項,某些位置有三個選項(出現次數不多于8次),并給出m個條件,每個條件要求x位置為p字符,則y位置為q字符,給出任意方案。
我們發現當所有位置只有兩種選項時,就是一道基礎的2-SAT題了。
設剛開始給的關于賽道條件的字符串為st,把不選擇表示為選擇。
對于一個條件
- 若st[x]=p,那么不會產生任何影響
- 若st[x]!=p,且st[y]=q,那么我們倘若選擇了p,則y位置為q,必然不合法,所以我們連一條的邊。
- 若st[x]!=p,且st[y]!=q,那么我們選擇了p,相當于選擇了q,所以連的邊和的邊。
直接tarjan,輸出方案即可。(不會輸出方案可以看?P4782?【模板】2-SAT 問題?的題解)
而現在某些位置有三個選項,但出現次數少于8,所以我們直接暴力枚舉這些位置選擇A還是B,每一次都做一遍上述的2-SAT過程即可。(感覺這題出在NOI2017簡直送分)
時間復雜度為O(怎么樣都能過)。
空間復雜度為O(怎么開都可以)。?
?
Code(這個編輯器怎么把我的縮進安排了啊):
? #include<bits/stdc++.h> using namespace std; const int MAXN=2e5+50; const char C[3][2]={{'B','C'},{'A','C'},{'A','B'}}; const int c[3][2]={{1,2},{0,2},{0,1}}; //用這兩個數組可以方便地判斷誰是這個位置的第一種方式char st[MAXN]; bool ins[MAXN]; int DFN,colornum,n,m,d; int dfn[MAXN],low[MAXN],color[MAXN]; int flag[MAXN],id[MAXN],chx[MAXN],chy[MAXN],X[MAXN],Y[MAXN]; vector<int> e[MAXN]; stack<int> stacks; void add_edge(int u,int v) { e[u].push_back(v); //cout<<u<<" "<<v<<endl; } inline int read() {int f=1,x=0; char c=getchar();while (c<'0'||c>'9') { if (c=='-') f=-1; c=getchar(); }while (c>='0'&&c<='9') { x=(x<<3)+(x<<1)+(c^48); c=getchar(); }return x*f; } inline char get_ch() {char c=getchar();while (c<'A'||c>'Z') c=getchar();return c; } void tarjan_init() {DFN=0; colornum=0;memset(dfn,0,sizeof dfn);memset(low,0,sizeof low);memset(color,0,sizeof color); } void tarjan(int x) {stacks.push(x);ins[x]=1;low[x]=dfn[x]=++DFN;for (int i=0;i<e[x].size();i++){int to=e[x][i];if (!dfn[to]){tarjan(to);low[x]=min(low[x],low[to]);}else if (ins[to]) low[x]=min(low[x],dfn[to]);}if (low[x]==dfn[x]){color[x]=++colornum;ins[x]=0;while (stacks.top()!=x){ins[stacks.top()]=0;color[stacks.top()]=colornum;stacks.pop();}stacks.pop();} } void make_graph() //分類討論,構圖 {for (int j=1;j<=n*2;j++) e[j].clear();for (int j=1;j<=m;j++) {//cout<<j<<":"<<endl;if (flag[X[j]]==chx[j]) continue; if (flag[Y[j]]==chy[j]) {if (chx[j]==c[flag[X[j]]][0]) add_edge(X[j],X[j]+n);else add_edge(X[j]+n,X[j]);//add_edge(X[j]+n,X[j]);add_edge(X[j],X[j]+n);}else {if (chx[j]==c[flag[X[j]]][0]) {if (chy[j]==c[flag[Y[j]]][0]) add_edge(X[j],Y[j]),add_edge(Y[j]+n,X[j]+n);else add_edge(X[j],Y[j]+n),add_edge(Y[j],X[j]+n);}else {if (chy[j]==c[flag[Y[j]]][0]) add_edge(X[j]+n,Y[j]),add_edge(Y[j]+n,X[j]); else add_edge(X[j]+n,Y[j]+n),add_edge(Y[j],X[j]);}}} } bool check() //判斷是否無解 {for (int j=1;j<=n;j++) if (color[j]==color[j+n]) return 0;return 1; } int main() {n=read(),d=read();scanf("%s",st+1);int xnum=0;for (int i=1;i<=n;i++){if (st[i]=='x') id[++xnum]=i;else flag[i]=st[i]-'a';}m=read();for (int i=1;i<=m;i++){X[i]=read(); chx[i]=get_ch()-'A'; Y[i]=read(); chy[i]=get_ch()-'A';}for (int i=0;i<(1<<d);i++){for (int j=0;j<d;j++) flag[id[j+1]]=((i>>j)&1);make_graph();tarjan_init();for (int j=1;j<=(n<<1);j++) if (!dfn[j]) tarjan(j);//cout<<endl; for (int j=1;j<=(n<<1);j++) cout<<j<<" "<<dfn[j]<<" "<<low[j]<<" "<<color[j]<<endl;if (!check()) continue;for (int j=1;j<=n;j++) putchar((color[j]<color[j+n])?C[flag[j]][0]:C[flag[j]][1]); //輸出方案return 0; }puts("-1");return 0;} /* 3 3 axb 5 1 A 3 B 1 B 2 A 1 C 2 C 2 A 3 B 2 B 3 B */??
總結
以上是生活随笔為你收集整理的P3825 [NOI2017]游戏的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [Wannafly挑战赛2D-Delet
- 下一篇: 数字游戏中的一种文学可能数字游戏中的一种