1. 程式人生 > >acd - 1403 - Graph Game(博弈 + 二分圖最大匹配)

acd - 1403 - Graph Game(博弈 + 二分圖最大匹配)

-- target ++i con -1 dsm return 中一 inf

題意:N與P在玩遊戲,N有 n1 個點,P有 n2 個點,N的點與P的點之間有 m 條無向邊。將一個石子放在當中一點。N先移動石子。沿邊移動一次,石子移動前的點及與該點相連的邊被刪除。接著到P移動石子,誰不能移動誰就輸。對每一個初始位置輸出勝負結果(1 ≤ n1; n2 ≤ 500, 0 ≤ m ≤ 50 000)。

題目鏈接:http://acdream.info/problem?pid=1403

——>>二分圖的最大匹配能夠有非常多種。可是,當中可能有些點,不管是哪一種最大匹配方案。都是已蓋點。

那麽。先手僅僅要從這種點沿著匹配邊走。就能夠把後手逼得走投無路。。

(為什麽呢?先手從 A 沿著匹配邊走到 B,後者從 B 走到還有一點 C。如果 C 不是已蓋點,則最大匹配的一條匹配邊 A - B 可改成 B - C,於是 A 不一定是已蓋點,不滿足我們的前提條件。

。所以。C 一定是已蓋點。於是先手能夠繼續沿著匹配邊走,最後把對手幹掉)

於是,兩邊各兩次dfs找出這種點就可以。。

#include <cstdio>
#include <cstring>

const int MAXN = 1000 + 10;
const int MAXM = 50000 + 10;

struct EDGE
{
    int to;
    int nxt;
} edge[MAXM << 1];

int n1, n2, m;
int hed[MAXN], ecnt;
int S[MAXN], T[MAXN];
bool vis[MAXN];
bool maxMatch[MAXN];

void Init()
{
    ecnt = 0;
    memset(hed, -1, sizeof(hed));
}

void AddEdge(int u, int v)
{
    edge[ecnt].to = v;
    edge[ecnt].nxt = hed[u];
    hed[u] = ecnt++;
}

void Read()
{
    int u, v;

    while (m--)
    {
        scanf("%d%d", &u, &v);
        AddEdge(u, v + n1);
        AddEdge(v + n1, u);
    }
    memset(maxMatch, 0, sizeof(maxMatch));
}

bool Match(int u)
{
    for (int e = hed[u]; e != -1; e = edge[e].nxt)
    {
        int v = edge[e].to;
        if (!vis[v])
        {
            vis[v] = true;
            int temps = S[u];
            int tempt = T[v];
            S[u] = v;
            T[v] = u;
            if (tempt == -1 || Match(tempt)) return true;
            T[v] = tempt;
            S[u] = temps;
        }
    }

    return false;
}

bool Judge(int u)
{
    vis[u] = true;
    if (S[u] == -1) return true;

    u = S[u];
    for (int e = hed[u]; e != -1; e = edge[e].nxt)
    {
        int v = edge[e].to;
        if (!vis[v] && Judge(v)) return true;
    }

    return false;
}

void GetMaxMatchPointLeft()
{
    memset(S, -1, sizeof(S));
    memset(T, -1, sizeof(T));
    for (int i = 1; i <= n1; ++i)
    {
        memset(vis, 0, sizeof(vis));
        if (Match(i))
        {
            maxMatch[i] = true;
        }
    }
    for (int i = 1 + n1; i <= n2 + n1; ++i)
    {
        if (T[i] != -1)
        {
            memset(vis, 0, sizeof(vis));
            if (Judge(T[i]))
            {
                maxMatch[T[i]] = false;
            }
        }
    }
}

void GetMaxMatchPointRight()
{
    memset(S, -1, sizeof(S));
    memset(T, -1, sizeof(T));
    for (int i = 1 + n1; i <= n2 + n1; ++i)
    {
        memset(vis, 0, sizeof(vis));
        if (Match(i))
        {
            maxMatch[i] = true;
        }
    }
    for (int i = 1; i <= n1; ++i)
    {
        if (T[i] != -1)
        {
            memset(vis, 0, sizeof(vis));
            if (Judge(T[i]))
            {
                maxMatch[T[i]] = false;
            }
        }
    }
}

void Output()
{
    for (int i = 1; i <= n1; ++i)
    {
        maxMatch[i] ? putchar('N') : putchar('P');
    }
    puts("");
    for (int i = 1 + n1; i <= n2 + n1; ++i)
    {
        maxMatch[i] ? putchar('N') : putchar('P');
    }
    puts("");
}

int main()
{
    while (scanf("%d%d%d", &n1, &n2, &m) == 3)
    {
        Init();
        Read();
        GetMaxMatchPointLeft();
        GetMaxMatchPointRight();
        Output();
    }

    return 0;
}


acd - 1403 - Graph Game(博弈 + 二分圖最大匹配)