Algoogle

Algorithm for Programming Contest

JOI 春合宿 2010 Lake

Category: JOI Tag: dp

Lake

問題概要


円周上に始点と終点がある航路がN個ある.
これらからいくつか交差する事のないように選ぶとき, 最大でいくつ選べるか

解法


まず指定された点以外は邪魔なので座圧する.
問題の図だと0をまたぐとき面倒そうに見えるが, そういう場合は向きを反転させれば全てが区間[0,2N)に収まる.
あとはO(N^2)でDPすればよい.
dp[l][r] := 区間[l,r]の中で選べる最大の個数
とすれば区間の幅が小さいものから順にできる.
もしlかrからその間に伸びる航路があるならそこで区切ってやる場合も試す.

コード


(lake.cpp) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <bits/stdc++.h>
using namespace std;

int n, zip[1<<19], s[2048], t[2048], dp[4096][4096], to[4096];
vector<int> vs;
inline void chmax(int &a, int b){ a=max(a,b);}

int solve()
{
        sort(begin(vs),end(vs));
        for (int i = 0; i < 2*n; i++) zip[vs[i]] = i;
        for (int i = 0; i < n; i++) {
                to[zip[s[i]]] = zip[t[i]];
                to[zip[t[i]]] = zip[s[i]];
        }

        n *= 2;
        for (int d = 1; d < n; d++) {
                for (int l = 0; l+d < n; l++) {
                        int r = l+d, p = to[l], q = to[r];
                        chmax(dp[l][r], dp[l][r-1]);
                        if(l < p and p <= r) chmax(dp[l][r], dp[l][p-1]+dp[p+1][r]+1);
                        if(l < q and q <= r) chmax(dp[l][r], dp[l][q-1]+dp[q+1][r]+1);
                }
        }
        return dp[0][n-1];
}

void input()
{
        cin >> n;
        for (int i = 0; i < n; i++) {
                cin >> s[i] >> t[i];
                if(s[i] > t[i]) swap(s[i], t[i]);
                vs.push_back(s[i]);
                vs.push_back(t[i]);
        }
}

int main()
{
        cin.tie(0);
        cin.sync_with_stdio(0);
        input();
        cout << solve() << endl;
        return 0;
}

Comments