avatar
fireworks99
keep hungry keep foolish

HDU 1281 Chessboard game(Bipartite graph match)

Description

N行M列的棋盘,空白地区放棋子“車”,使彼此不能攻击到,非空白地区不影响彼此的攻击(不是“墙”),求在放最多“車”的前提下,有几个点是“重要点”(棋子不放在这里就会减少可放棋子数)?

Analyze

同HDU 1045 Fire Net类似,解法思想(二分图匹配)也相同

方案一 较为暴力

求完最大匹配后,将每条匹配的边撤掉再求一遍最大匹配,看是否减少,若减少则该边对应点是最要点。

Code

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 105;

int n, m, k;
bool vis[N];
int mp[N][N], link[N], t_link[N];

///DFS(int x): link[to] = x not link[x] = to

bool DFS(int x)
{
    for(int i = 1; i <= n; ++i)
        if(mp[x][i] && !vis[i])
        {
            vis[i] = 1;
            if(link[i] == -1 || DFS(link[i]))
            {
                link[i] = x;
                return 1;
            }
        }
    return 0;
}

int solve()
{
    int res = 0;
    memset(link, -1, sizeof(link));
    for(int i = 1; i <= n; ++i)
    {
        memset(vis, 0, sizeof(vis));
        if(DFS(i))
            res++;
    }
    return res;
}

int main()
{
    int CASE = 1;
    while(~scanf("%d %d %d", &n, &m, &k))
    {
        memset(mp, 0, sizeof(mp));
        int u, v;
        for(int i = 0; i < k; ++i)
        {
            scanf("%d %d", &u, &v);
            mp[u][v] = 1;
        }

        int num = solve();

        int ans = 0;
        memcpy(t_link, link, sizeof(link));
        for(int i = 1; i <= n; ++i)
            if(t_link[i] != -1)
            {
                mp[ t_link[i] ][i] = 0;
                int t_num = solve();
                if(t_num != num)
                    ans++;
                mp[ t_link[i] ][i] = 1;
            }
        printf("Board %d have %d important blanks for %d chessmen.\n", CASE++, ans, num);
    }
    return 0;
}

方案二 小题大做

同HDU 4685,添加虚点,求最大匹配,缩点。

这样做麻烦些,不仅可以得到“重要点”的个数,还可以得出”重要点“是哪些

Code

#include <stack>
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 105 * 4;
const int M = 2 * N * N;
const int base = 100;

int n, m, k;
bool love[N][N];

int head[N], cnt;
struct edge
{
    int v, pre;
} e[M];

void add(int u, int v)
{
    e[cnt].v = v;
    e[cnt].pre = head[u];
    head[u] = cnt++;
}

bool vis[N];
int girl[N], boy[N];
bool DFS(int x)
{
    for(int i = head[x]; ~i; i = e[i].pre)
    {
        int to = e[i].v;
        if(!vis[to])
        {
            vis[to] = 1;
            if(!girl[to] || DFS(girl[to]))
            {
                girl[to] = x;
                boy[x] = to;
                return 1;
            }
        }
    }
    return 0;
}

int Match()
{
    int res = 0;
    for(int i = 1; i <= n; ++i)
    {
        memset(vis, 0, sizeof(vis));
        if(DFS(i))
            res++;
    }
    return res;
}

bool inst[N];
stack<int> st;
vector<int> scc[N];
int low[N], times[N], t, num, ltt[N];
void Tarjan(int x)
{
    st.push(x);
    inst[x] = 1;
    low[x] = times[x] = ++t;
    for(int i = head[x]; ~i; i = e[i].pre)
    {
        int to = e[i].v;
        if(!times[to])
        {
            Tarjan(to);
            low[x] = min(low[x], low[to]);
        }
        else if(inst[to])
            low[x] = min(low[x], times[to]);
    }

    if(low[x] == times[x])
    {
        ++num;
        while(!st.empty())
        {
            int tem = st.top();
            st.pop();
            ltt[tem] = num;
            inst[tem] = 0;

            if(tem > base && tem <= 2 * base)///This is a girl.
                scc[num].push_back(tem - base);

            if(tem == x)
                break;
        }
    }
}

void init()
{
    for(int i = 0; i <= num; ++i)
        scc[i].clear();
    cnt = t = num = 0;
    while(!st.empty())
        st.pop();
    memset(ltt, 0, sizeof(ltt));
    memset(boy, 0, sizeof(boy));
    memset(girl, 0, sizeof(girl));
    memset(love, 0, sizeof(love));
    memset(inst, 0, sizeof(inst));
    memset(head, -1, sizeof(head));
    memset(times, 0, sizeof(times));
}

int main()
{
    int CASE = 1;
    while(~scanf("%d %d %d", &n, &m, &k))
    {
        init();
        int u, v;
        for(int i = 0; i < k; ++i)
        {
            scanf("%d %d", &u, &v);
            love[u][v] = 1;
            add(u, base + v);
        }

        int matches = Match();

        int node = 0;
        for(int i = 1; i <= n; ++i)
            if(!boy[i])
            {
                ++node;
                v = 2 * base + node;
                boy[i] = v, girl[v] = i;

                for(int j = 1; j <= n; ++j)
                    add(j, v);
            }
        for(int i = base + 1; i <= base + m; ++i)
            if(!girl[i])
            {
                ++node;
                v = 2 * base + node;
                girl[i] = v, boy[v] = i;

                for(int j = base + 1; j <= base + m; ++j)
                    add(v, j);
            }

        for(int i = base + 1; i <= base * 2 + node; ++i)
            add(i, girl[i]);///Opposite edges

        for(int i = 1; i <= n; ++i)
            if(!times[i])
                Tarjan(i);

        int tot, ans = 0;
        for(int i = 1; i <= n; ++i)
        {
            tot = 0;
            int sz = scc[ ltt[i] ].size();
            for(int j = 0; j < sz; ++j)
            {
                v = scc[ ltt[i] ][j];
                if(love[i][v])
                    tot++;
            }
            if(tot == 1)
                ans++;
        }
        printf("Board %d have %d important blanks for %d chessmen.\n", CASE++, ans, matches);
    }
    return 0;
}
Site by Baole Zhao | Powered by Hexo | theme PreciousJoy