Rochambeau 【POJ - 2912】【列舉+種類並查集】
阿新 • • 發佈:2018-12-25
題目連結
題意:有N個小夥伴進行猜拳有戲,除了一個比較聰明的傢伙以外,其他人只會出單一的一種,給出m中猜拳的結果,要求找出那個比較聰明的小夥伴序號,並且輸出在第幾次猜拳可以確定。註明:"<"、">"、"="前後不會有空格。
500個人的資料,一開始想寫個直接種類並查集(像食物鏈一樣),但是發現,會有問題,你不知道這條鏈上兩端的,誰是出千的那個老弟,所以,我們不能這麼弄,於是,資料不大,就想到了用種類並查集+列舉誰是出千的人。
那麼,還要考慮到輸出時間,我一開始開了兩個並查集,並且兩套種類儲存的陣列,發現會WA(一會貼上WA的程式碼),然後發現,這樣子會不行,得想辦法優化它,這樣子我們能得到結果,但是時間上會出現問題,那麼,怎麼優化就可以得到時間?這個時間,表明了就是對應只有1個確定解的時候,那麼就是當它不是我們所查詢區間的時候的其他最大的時間不就是我們想要知道的解了嗎?
所以,當我們知道以該人為出千的人且不行的時候,記錄下對應的時間點,這個判斷的時間點就表明了它不是正解,並且在該時間點上有衝突項。
接下來,就是輸出了:如果沒找到答案,說明各自都有衝突項,不行!如果找到了一個答案,那麼,就是它了;如果找到了多個答案,就說明是還不確定的解。
Accept程式碼:
#include <iostream> #include <cstdio> #include <cmath> #include <string> #include <cstring> #include <algorithm> #include <limits> #include <vector> #include <stack> #include <queue> #include <set> #include <map> #define lowbit(x) ( x&(-x) ) #define pi 3.141592653589793 #define e 2.718281828459045 #define INF 10000007. #define efs 1e-6 using namespace std; typedef unsigned long long ull; typedef long long ll; const int maxN = 505; struct Ques //可以直接列舉+並查集、儲存查詢 { int x, y, val; Ques(int a=0, int b=0, int c=0):x(a), y(b), val(c) {} }q[maxN<<2]; int N, M, root[maxN], sum[maxN], ans, day, state, time_need[maxN]; char op; int fid(int x) { if(x == root[x]) return x; int tmp = root[x]; root[x] = fid(root[x]); sum[x] = (sum[x] + sum[tmp] + 3)%3; return root[x]; } void init() { for(int i=0; i<=N; i++) { root[i] = i; sum[i] = 0; } } int solve(int pos) { bool flag = true; init(); int date = 0; for(int i=1; i<=M; i++) { int x = q[i].x, y = q[i].y, tmp = q[i].val; if(x == pos || y == pos) { continue; } int u = fid(x), v = fid(y); if(u != v) { root[v] = u; sum[v] = (sum[x] - sum[y] + tmp + 3)%3; } else { if((sum[y] - sum[x] + 3)%3 != tmp) { flag = false; time_need[pos] = i; break; } } } return flag?date:(-1); } int main() { while(scanf("%d%d", &N, &M)!=EOF) { int x, y; for(int i=1; i<=M; i++) { scanf("%d%c%d", &x, &op, &y); int tmp = 0; if(op == '<') tmp = 1; else if(op == '>') tmp = 2; q[i] = Ques(x, y, tmp); } state = day = 0; memset(time_need, 0, sizeof(time_need)); for(int i=0; i<N; i++) { int tmp = solve(i); if(tmp == -1) continue; ans = i; state++; } for(int i=0; i<N; i++) if(i!=ans && day < time_need[i]) day = time_need[i]; if(state == 0) printf("Impossible\n"); else if(state == 1) printf("Player %d can be determined to be the judge after %d lines\n", ans, day); else printf("Can not determine\n"); } return 0; }
接下來,還有個WA的程式碼,供大家參考:
Wrong的程式碼:
#include <iostream> #include <cstdio> #include <cmath> #include <string> #include <cstring> #include <algorithm> #include <limits> #include <vector> #include <stack> #include <queue> #include <set> #include <map> #define lowbit(x) ( x&(-x) ) #define pi 3.141592653589793 #define e 2.718281828459045 #define INF 10000007. #define efs 1e-6 using namespace std; typedef unsigned long long ull; typedef long long ll; const int maxN = 505; struct Ques //可以直接列舉+並查集、儲存查詢 { int x, y, val; Ques(int a=0, int b=0, int c=0):x(a), y(b), val(c) {} }q[maxN<<2]; int N, M, root[maxN], sum[maxN], ans, day, state, fa[maxN], keys[maxN]; char op; int fid(int x) { if(x == root[x]) return x; int tmp = root[x]; root[x] = fid(root[x]); sum[x] = (sum[x] + sum[tmp] + 3)%3; return root[x]; } int father(int x) { if(x == fa[x]) return x; int tmp = fa[x]; fa[x] = father(fa[x]); keys[x] = (keys[x] + keys[tmp] + 3)%3; return fa[x]; } void init() { for(int i=0; i<=N; i++) { root[i] = i; fa[i] = i; sum[i] = keys[i] = 0; } } int solve(int pos) { bool flag = true; init(); int date = 0, cnt = 0; for(int i=1; i<=M; i++) { int x = q[i].x, y = q[i].y, tmp = q[i].val; if(x == pos || y == pos) { int u = father(x), v = father(y); if(u != v) { fa[v] = u; keys[v] = (keys[x] - keys[y] + tmp + 3)%3; } else { if((keys[y] - keys[x] + 3)%3 != tmp) { cnt++; if(cnt >= 2) { if(!date) date = i; } } } continue; } int u = fid(x), v = fid(y); if(u != v) { root[v] = u; sum[v] = (sum[x] - sum[y] + tmp + 3)%3; } else { if((sum[y] - sum[x] + 3)%3 != tmp) { flag = false; break; } } } return flag?date:(-1); } int main() { while(scanf("%d%d", &N, &M)!=EOF) { int x, y; state = 0; for(int i=1; i<=M; i++) { scanf("%d%c%d", &x, &op, &y); int tmp = 0; if(op == '<') tmp = 1; else if(op == '>') tmp = 2; q[i] = Ques(x, y, tmp); } for(int i=0; i<N; i++) { int tmp = solve(i); if(tmp == -1) continue; ans = i; day = tmp; state++; } if(state == 0) printf("Impossible\n"); else if(state == 1) printf("Player %d can be determined to be the judge after %d lines\n", ans, day); else printf("Can not determine\n"); } return 0; }
Wrong的程式碼,與Accept的程式碼,差別僅在於處理時間的問題上,輸出的時間是不一樣的,因為WA的程式碼,沒有考慮到相互間的關係。不能直接判斷衝突。