avatar
fireworks99
keep hungry keep foolish

HDU 1045 Fire Net(DFS or bipartite graph match)

Description

给出一个地图,有空地,有墙,在空地上安排炮台,炮台会向四方攻击,但不会穿透墙壁,要避免炮台彼此攻击到,求最多能安排多少炮台?

Analyze

可以简单のDFS

另外的二分图匹配:

假设没有墙壁,为每行、每列标号,针对每个点进行建边,求最大匹配

1 1 1 1
2 2 2 2
3 3 3 3
4 4 4 4
1 2 3 4
1 2 3 4
1 2 3 4
1 2 3 4

建边add(1, 1)add(1, 2)add(1, 3)add(1,4)add(2,1)……

在求最大匹配时,假设第一个表中的2匹配了第二个表中的3,那么相当于在第二行第三列建一座炮台,由于本行都是2,且2已经被分配,所以本行不会再被分配炮台;同理,本列都是3,且3已经被分配,所以本列不会再被分配炮台。如此限制了同行或同列不会出现两座炮台。

现在有墙,标号便可增加了,比如样例

4
.X..
....
XX..
....
1 X 2 2
3 3 3 3
X X 4 4
5 5 5 5
1 X 5 6
1 3 5 6
X X 5 6
2 4 5 6

Code

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int N = 205;
char s[N][N];
int n, mat[N], idr, idc, gr[N][N], gc[N][N];
bool vis[N], g[N][N];

bool dfs(int u)
{
    for (int v = 1; v <= idc; v++)
    {
        if (vis[v] || !g[u][v])
            continue;
        vis[v] = 1;
        if (!mat[v] || dfs(mat[v]))
        {
            mat[v] = u;
            return 1;
        }
    }
    return 0;
}

int main()
{
    while (scanf("%d", &n), n)
    {
        memset(g, false, sizeof(g));
        memset(gr, 0, sizeof(gr));
        memset(gc, 0, sizeof(gc));
        memset(mat, 0, sizeof(g));
        for (int i = 0; i < n; i++)
            scanf("%s", s[i]);

        idr = 0;
        for (int i = 0; i < n; i++)
        {
            idr++;
            for (int j = 0; j < n; j++)
            {
                if (s[i][j] == 'X')
                {
                    if (j != 0 && j != n - 1)
                        idr++;
                    continue;
                }
                gr[i][j] = idr;
            }
        }
        idc = 0;
        for (int j = 0; j < n; j++)
        {
            idc++;
            for (int i = 0; i < n; i++)
            {
                if (s[i][j] == 'X')
                {
                    if (i != 0 && i != n - 1)
                        idc++;
                    continue;
                }
                gc[i][j] = idc;
            }
        }

        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < n; j++)
            {
                if (s[i][j] == 'X')
                    continue;
                int u = gr[i][j], v = gc[i][j];
                g[u][v] = true;
            }
        }

        int ans = 0;
        for (int i = 1; i <= idr; i++)
        {
            memset(vis, false, sizeof(vis));
            if (dfs(i))
                ans++;
        }
        printf("%d\n", ans);
    }
    return 0;
}

Code of DFS

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

int n, ans;
char mp[10][10];

bool check(int x, int y)
{
    if(mp[x][y] != '.')
        return 0;
    for(int i = y - 1; i >= 0; --i)
        if(mp[x][i] == 'B')
            return 0;
        else if(mp[x][i] == 'X')
            break;
    for(int i = x - 1; i >= 0; --i)
        if(mp[i][y] == 'B')
            return 0;
        else if(mp[i][y] == 'X')
            break;
    return 1;
}

void DFS(int pos, int num)
{
    if(pos == n * n)
    {
        ans = max(ans, num);
        return ;
    }
    int x = pos / n, y = pos % n;
    if(check(x, y))
    {
        mp[x][y] = 'B';
        DFS(pos + 1, num + 1);
        mp[x][y] = '.';
    }
    DFS(pos + 1, num);
    return ;
}

int main()
{
    while(~scanf("%d", &n) && n)
    {
        for(int i = 0; i < n; ++i)
            scanf("%s", mp[i]);
        ans = 0;
        DFS(0, 0);
        cout << ans << '\n';
    }
    return 0;
}
Site by Baole Zhao | Powered by Hexo | theme PreciousJoy