CF1272E. Nearest Opposite Parity 題解 廣度優先搜索

題目連接:http://codeforces.com/contest/1272/problem/Ec++

題目大意:
有一個長度爲n的數組 \(a\) ,數組座標從 \(1\)\(n\)
假設你如今處於數組中的某一個位置,咱們假設這個座標爲 \(i\) ,那麼:
若是 \(1 <= i-a[i]\) ,那麼你能夠從座標 \(i\) 移動到座標 \(i-a[i]\) 位置(花費一步);
若是 \(i+a[i]<=n\) ,那麼你能夠從座標 \(i\) 移動到座標 \(i+a[i]\) 位置(一樣花費一步)。
對於從 \(1\)\(n\) 的全部座標 \(i\) 來講,你想要的知道你最少須要幾步能夠從座標 \(i\) 移動到一個座標\(j\)
\(a[i]\)\(a[j]\) 具備不一樣的奇偶性(也就是說,若是 \(a[i]\) 是偶數,那麼 \(a[j]\) 就是奇數;若是 \(a[i]\) 是奇數,那麼 \(a[j]\) 就得是偶數)。算法

解題思路:
這個問題能夠轉換成圖論模型,而後用廣度優先搜索或者最短路算法(Dijkstra或者SPFA算法)進行求解。
這裏由於可能有些同窗沒有學到最短路算法,而且用最短路算法解決廣搜能夠解決的問題有一點殺雞用牛刀的感受(今年CSP-J複賽第4題能夠用廣搜作然而我也用了最短路SPFA算法),因此我這裏仍是講解廣度優先搜索解決這個問題。
對於一個邊權均爲 \(1\) 的圖來講,咱們經過廣度優先搜索獲得的就是最短路。由於此時一開始入隊列的都是距起點 \(0\) 的點,而後入隊列的是距起點 \(1\) 的點,而後入隊列的是距起點 \(2\) 的點,……(你們能夠本身畫圖體會一下,此時的廣度優先搜索就是一個層次遍歷)數組

而後咱們來看怎麼使用廣度優先搜索解決這個問題。spa

首先對於 \(a[i]\) 來講,code

  • 若是 \(i-a[i] \ge 1\),則從 \(i-a[i]\)\(i\) 連一條邊;
  • 若是 \(i+a[i] \le n\),則從 \(i+a[i]\)\(i\) 連一條邊。

而後就能夠開始咱們的搜索了。
在搜索以前咱們須要先開兩個數組:隊列

  • \(odd[i]\) 表示座標爲 \(i\) 的點到達最近的一個奇數點所需的最少步數;
  • \(even[i]\) 表示座標爲 \(i\) 的點到達最近的一個偶數點所需的最少步數。

咱們先來求 \(odd\) 值,
咱們從 \(1\)\(n\) 遍歷 \(i\)ci

  • 若是 \(a[i]\) 是奇數,則設 \(odd[i]\)\(0\),同時將其加入隊列;
  • 不然(\(a[i]\) 爲偶數),設 \(odd[i]\) 爲無窮大。

接下來每次從隊列裏面取出一個座標 \(u\),而後遍歷全部 \(u\) 能夠到達的點 \(v\) ,若是 \(odd[v] > odd[u]+1\) ,則標記 \(odd[v] = odd[u]+1\) ,同時將 \(v\) 加入隊列。get

最終每一個點的 \(odd\) 值即表示從座標 \(i\) 出發最少須要花費多少步可以到達一個奇數值得點。it

而後咱們再來求 \(even\) 值(其實大家會發現是同樣的道理),
咱們從 \(1\)\(n\) 遍歷 \(i\)class

  • 若是 \(a[i]\) 是偶數,則設 \(odd[i]\)\(0\),同時將其加入隊列;
  • 不然(\(a[i]\) 爲奇數),設 \(odd[i]\) 爲無窮大。

接下來每次從隊列裏面取出一個座標 \(u\),而後遍歷全部 \(u\) 能夠到達的點 \(v\) ,若是 \(odd[v] > odd[u]+1\) ,則標記 \(odd[v] = odd[u]+1\) ,同時將 \(v\) 加入隊列。

自此,咱們就求解完了 \(odd\)\(even\) 值。

而後咱們從 \(1\)\(n\) 遍歷座標 \(i\)

  • 若是 \(a[i]\) 是奇數,輸出 \(even[i]\)
  • 若是 \(a[i]\) 是偶數,輸出 \(odd[i]\)

實現代碼以下:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 200020;
int n, a[maxn], odd[maxn], even[maxn];
vector<int> g[maxn];
queue<int> que;
int main() {
    cin >> n;
    for (int i = 1; i <= n; i ++) cin >> a[i];
    for (int i = 1; i <= n; i ++) {
        if (i-a[i] >= 1) g[ i-a[i] ].push_back(i);
        if (i+a[i] <= n) g[ i+a[i] ].push_back(i);
    }
    // odd
    for (int i = 1; i <= n; i ++) {
        if (a[i]%2) {
            odd[i] = 0;
            que.push(i);
        }
        else odd[i] = -1;
    }
    while (!que.empty()) {
        int u = que.front();
        que.pop();
        int sz = g[u].size();
        for (int i = 0; i < sz; i ++) {
            int v = g[u][i];
            if (odd[v] == -1 || odd[v] > odd[u] + 1) {
                odd[v] = odd[u] + 1;
                que.push(v);
            }
        }
    }
    // even
    for (int i = 1; i <= n; i ++) {
        if (a[i] % 2 == 0) {
            even[i] = 0;
            que.push(i);
        }
        else even[i] = -1;
    }
    while (!que.empty()) {
        int u = que.front();
        que.pop();
        int sz = g[u].size();
        for (int i = 0; i < sz; i ++) {
            int v = g[u][i];
            if (even[v] == -1 || even[v] > even[u] + 1) {
                even[v] = even[u] + 1;
                que.push(v);
            }
        }
    }
    for (int i = 1; i <= n; i ++) {
        if (i > 1) putchar(' ');
        if (a[i] % 2) cout << even[i];
        else cout << odd[i];
    }
    cout << endl;
    return 0;
}
相關文章
相關標籤/搜索