@atcoder - 二つの順列@ AGC038F


@説明@

2つのPがQ.、N 0〜N-1である置き換えを考えます
今、あなたは2つの順列のAとBを見つける必要があり、その結果、[I] = P [I ] またはI; B [i]は= Q [i]のか、私。
IはBの数であり、[I] A [i]の≠最大化されます。最大出力。

制約
。100000≤1≤N ..
P 0〜N-1であることを保証するために配置されています。
Qは0〜N-1であることを保証するために配置されています。

入力
フォーム以下の入力:
N
。P0 P1の1⋯PN-
Q0-QN 1⋯Q1を。

出力
出力A [i]には≠Bの最大数のI [I]です。

サンプル入力1
4
2 1 3 0
0 2 3 1
サンプル出力1
3

一つの解決策は、=(0,1,2,3)、B =(0,2,3,1)です。

サンプル入力2
10
0 4 5 7 3 8 2 1 9 6
3 8 5 6 4 0 2 1 7 9
サンプル出力2
8

サンプル入力3
32
22 31 30 29 7 17 16 3 14 9 19 11 2 5 10 1 25 18 15 24 20 0 12 21 27 4 26 28 8 6 23 13
22 3 2 7 17 9 16 4 14 8 19 26 28 5 10 1 25 18 15 13 11 0 12 23 21 20 29 24 27 6 30 31
出力例3
28

@解決@

Pの交換のために、我々はいくつかのサイクルにそれを打破します。
維持またはP [i]は不変ながらサイクル毎に、いずれかの同時に選択は、Iとなります。
各要素は、2つのオプションがありますが、人々は2-SATは考えられない、お互いの選択に影響を与える最小カットの思想である(最小制限時間がさらにカット意味します!)。

最小カット変換は:我々は、最小A [I] = B [I見つける ] 数。
各サイクルのために、我々はサイクルのすべてのポイントに双方向側INFのも、容量を仮想点を構築します。
残りはマップ(:選挙の費用のような問題を生成する一方IE)を内蔵し、古典的なバイナリの関係です。

選択したiに接続されたソースを表す各パイ、のために、Piは、それがシンクを表す接続するために選択されます。
選択されたチーに接続されたソースを表す各チー、のために、私もシンクことを示す選択しました。
エッジは、その後、I、PI、チーの間の対等な関係を築いて分類されます。特定のコードを見ることができます。
対称構造が負の右側が生成されますので、非対称性が構築された理由については、良いではありません。

@acceptedコード@

#include<queue>
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN = 100000;
const int INF = (1<<30);
struct FlowGraph{
    struct edge{
        int to, cap, flow;
        edge *nxt, *rev;
    }edges[20*MAXN + 5], *adj[4*MAXN + 5], *cur[4*MAXN + 5], *ecnt;
    FlowGraph() {ecnt = &edges[0];}
    void addedge(int u, int v, int c1, int c2) {
        edge *p = (++ecnt), *q = (++ecnt);
        p->to = v, p->cap = c1, p->flow = 0;
        p->nxt = adj[u], adj[u] = p;
        q->to = u, q->cap = c2, q->flow = 0;
        q->nxt = adj[v], adj[v] = q;
        p->rev = q, q->rev = p;
//      printf("! %d %d %d %d\n", u, v, c1, c2);
    }
    int dis[4*MAXN + 5];
    int s, t;
    bool relabel() {
        for(int i=0;i<=t;i++)
            dis[i] = INF, cur[i] = adj[i];
        queue<int>que; que.push(t), dis[t] = 0;
        while( !que.empty() ) {
            int f = que.front(); que.pop();
            for(edge *p=adj[f];p;p=p->nxt)
                if( p->rev->cap > p->rev->flow )
                    if( dis[f] + 1 < dis[p->to] )
                        que.push(p->to), dis[p->to] = dis[f] + 1;
        }
        return !(dis[s] == INF);
    }
    int aug(int x, int tot) {
        if( x == t ) return tot;
        int sum = 0;
        for(edge *&p=cur[x];p;p=p->nxt) {
            if( p->cap > p->flow && dis[p->to] + 1 == dis[x] ) {
                int del = aug(p->to, min(p->cap - p->flow, tot - sum));
                sum += del, p->flow += del, p->rev->flow -= del;
                if( sum == tot ) break;
            }
        }
        return sum;
    }
    int max_flow(int _s, int _t) {
        int flow = 0; s = _s, t = _t;
        while( relabel() )
            flow += aug(s, INF);
        return flow;
    }
}G;
int P[MAXN + 5], Q[MAXN + 5];
bool tag[MAXN + 5];
int main() {
    int N, cnt; scanf("%d", &N), cnt = 2*N;
    for(int i=1;i<=N;i++)
        scanf("%d", &P[i]), P[i]++, tag[i] = false;
    for(int i=1;i<=N;i++)
        if( !tag[i] ) {
            int p = i; cnt++;
            do {
                tag[p] = true;
                p = P[p];
                G.addedge(cnt, p, INF, INF);
            }while( p != i );
        }
    for(int i=1;i<=N;i++)
        scanf("%d", &Q[i]), Q[i]++, tag[i] = false;
    for(int i=1;i<=N;i++)
        if( !tag[i] ) {
            int p = i; cnt++;
            do {
                tag[p] = true;
                p = Q[p];
                G.addedge(cnt, p + N, INF, INF);
            }while( p != i );
        }
    int s = 0, t = cnt + 1;
    for(int i=1;i<=N;i++) {
        if( i == P[i] && i == Q[i] && P[i] == Q[i] )// a = c = 1
            G.addedge(s, i, 1, 0), G.addedge(i, t, 1, 0);
        if( i == P[i] && i != Q[i] && P[i] != Q[i] )// b = 1
            G.addedge(s, i + N, 1, 0);
        if( i != P[i] && i == Q[i] && P[i] != Q[i] )// c = 1
            G.addedge(i, t, 1, 0);
        if( i != P[i] && i != Q[i] && P[i] == Q[i] )// e = f = 1
            G.addedge(i, i + N, 1, 1);
        if( i != P[i] && i != Q[i] && P[i] != Q[i] )// f = 1
            G.addedge(i, i + N, 1, 0);
    }//s -> i(a), s -> i+N(b), i -> t(c), i+N -> t(d), i+N -> i(e), i -> i+N(f)
    printf("%d\n", N - G.max_flow(s, t));
}

@詳細@

どのようにE F話題のタイトルああよりも水の感覚。それはそれは私の想像です。

おすすめ

転載: www.cnblogs.com/Tiw-Air-OAO/p/11688690.html