二分匹配-hdu-1045-Fire Net

来源:互联网 发布:多彩贵州网络印象直播 编辑:程序博客网 时间:2024/05/17 23:04

Suppose that we have a square city with straight streets. A map of a city is a square board with n rows and n columns, each representing a street or a piece of wall.

A blockhouse is a small castle that has four openings through which to shoot. The four openings are facing North, East, South, and West, respectively. There will be one machine gun shooting through each opening.

Here we assume that a bullet is so powerful that it can run across any distance and destroy a blockhouse on its way. On the other hand, a wall is so strongly built that can stop the bullets.

The goal is to place as many blockhouses in a city as possible so that no two can destroy each other. A configuration of blockhouses is legal provided that no two blockhouses are on the same horizontal row or vertical column in a map unless there is at least one wall separating them. In this problem we will consider small square cities (at most 4x4) that contain walls through which bullets cannot run through.

The following image shows five pictures of the same board. The first picture is the empty board, the second and third pictures show legal configurations, and the fourth and fifth pictures show illegal configurations. For this board, the maximum number of blockhouses in a legal configuration is 5; the second picture shows one way to do it, but there are several other ways.

这里写图片描述

Your task is to write a program that, given a description of a map, calculates the maximum number of blockhouses that can be placed in the city in a legal configuration.
Input
The input file contains one or more map descriptions, followed by a line containing the number 0 that signals the end of the file. Each map description begins with a line containing a positive integer n that is the size of the city; n will be at most 4. The next n lines each describe one row of the map, with a ‘.’ indicating an open space and an uppercase ‘X’ indicating a wall. There are no spaces in the input file.
Output
For each test case, output one line containing the maximum number of blockhouses that can be placed in the city in a legal configuration.
Sample Input
4
.X..
….
XX..
….
2
XX
.X
3
.X.
X.X
.X.
3

.XX
.XX
4
….
….
….
….
0
Sample Output
5
1
5
2
4

题目大意:
给你一个nxn的空间,”X”代表墙,该位置不能放blockhouse,”.”代表该位置可以放置blockhouse,blockhouse可以向东南西北四个方向发射炮弹,炮弹可以穿透blockhouse,但是不能穿透强,题目要求求出在没有任何一个blockhouse被炮弹穿透的情况下,nxn空间能放置的最多blockhouse数目
解题思路:
一般来说..首先会想到用搜索…
但是最近复习了二分图..就用二分图写了…
主要是建图,方法比较奇特..看了人家的思路才知道是怎么建的,
这里写图片描述
这里写图片描述
我们要知道只有在墙体的阻隔之下,才会出现大于1个blockhouse放在同一行或者同一列的情况,所以我们可以进行缩点,把在同一行且没有墙体阻隔的方格缩成一个点,这些点放在集合A中,同理:把在同一列且没有墙体阻隔的方格缩成一个点,这些点放在集合B中,用A和B点集构成一个二分图,那啥时候两个点之间有边的存在呢,行缩点后点的编号为1-5,列缩点后点的编号为-6,假如i(行编号),j(列编号),如果i和j之间有一条边的话,就相当于假设方格(i,j)位置上放置了blockhouses,这个假设会使得在没有墙体阻隔的情况下,i行,j列都不能再放其他的blockhouses;
我们在不考虑限制条件(不能同行同列)的情况下,把所有的边都连起来,行列缩点后,对应方格的编号连边
这里写图片描述
不小心举得例子的图有点复杂了..
在该二分图上求最大二分匹配(在每个点最多只被用到一次的情况下,就相当于在没有墙体阻隔的情况下同行或者同列只能放一个blockhouses)…就是答案了

#include <iostream>#include <stdio.h>#include <queue>#include <vector>#include <string.h>using namespace std;int n,m;int linker[20];int used[20];int head[20],tot;char a[10][10];int r[16][16],l[16][16];struct edge{    int to,next;} edge[20*20];void init(){    tot=0;    memset(head,-1,sizeof(head));    memset(r,-1,sizeof(r));    memset(l,-1,sizeof(l));}void addedge(int u,int v){    edge[tot].to=v;    edge[tot].next=head[u];    head[u]=tot++;}bool dfs(int u){    for(int i=head[u]; i!=-1; i=edge[i].next)    {        int v=edge[i].to;        if(!used[v])        {            used[v]=1;            if(linker[v]==-1||dfs(linker[v]))            {                linker[v]=u;                return true;            }        }    }    return false;}int hungary(){    int res=0;    memset(linker,-1,sizeof(linker));    for(int u=0; u<=m; u++)    {        memset(used,0,sizeof(used));        if(dfs(u)) res++;    }    return res;}int main(){    while(cin>>n&&n)    {        init();        for(int i=0; i<n; i++)            cin>>a[i];        int tmp=0;        for(int i=0; i<n; i++)        {            tmp++;             for(int j=0; j<n; j++)            {                if(a[i][j]=='X')                    tmp++;                else                    r[i][j]=tmp;            }        }        m=tmp;///记得记录下缩点后点的数目,在后面需要使用到,不然会出错..        tmp=0;        for(int j=0; j<n; j++)        {            tmp++;             for(int i=0; i<n; i++)            {                if(a[i][j]=='X')                    tmp++;                else                    l[i][j]=tmp;            }        }        for(int i=0; i<n; i++)            for(int j=0; j<n; j++)            {                if(r[i][j]!=-1&&l[i][j]!=-1)                    addedge(r[i][j],l[i][j]);            }            int ans=hungary();            printf("%d\n",ans);    }}
原创粉丝点击