1. 程式人生 > >hdu 5556 Land of Farms【思維+暴力列舉+最大獨立集】好題!

hdu 5556 Land of Farms【思維+暴力列舉+最大獨立集】好題!

Land of Farms

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 526    Accepted Submission(s): 174

Problem Description

Farmer John and his brothers have found a new land. They are so excited and decide to build new farms on the land. The land is a rectangle and consists of N×Mgrids. A farm consists of one or more connected grids. Two grids are adjacent if they share a common border, i.e. their Manhattan distance is exactly 1. In a farm, two grids are considered connected if there exist a series of adjacent grids, which also belong to that farm, between them.

Farmer John wants to build as many farms as possible on the new land. It is required that any two farms should not be adjacent. Otherwise, sheep from different farms would fight on the border. This should be an easy task until several ancient farms are discovered.

Each of the ancient farms also consists of one or more connected grids. Due to the respect to the ancient farmers, Farmer John do not want to divide any ancient farm. If a grid from an ancient farm is selected in a new farm, other grids from the ancient farm should also be selected in the new farm. Note that the ancient farms may be adjacent, because ancient sheep do not fight each other.

The problem is a little complicated now. Can you help Farmer John to find a plan with the maximum number of farms?

Input

The first line of input contains a number T indicating the number of test cases (T≤200).

Each test case starts with a line containing two integers N and M, indicating the size of the land. Each of the following N lines contains M characters, describing the map of the land (1≤N,M≤10). A grid of an ancient farm is indicated by a single digit (0-9). Grids with the same digit belong to the same ancient farm. Other grids are denoted with a single character “.

”. It is guaranteed that all test cases are valid.

Output

For each test case, output a single line consisting of “Case #X: Y”. X is the test case number starting from 1. Y is the maximum number of new farms.

Sample Input

3

3 4

..3.

023.

.211

2 3

...

...

4 4

1111

1..1

1991

1111

Sample Output

Case #1: 4

Case #2: 3

Case #3: 1

Source

題目大意:

一個N*M的矩陣,其中“.”代表空地,“0-9”代表古代建築,我們如果選擇了一個編號的古代建築想要建立,那麼對應就要將全部該編號的建築建立起來,如果在空地上建築,只建立當前點。問最多能夠建立多少種建築,並且每兩種建築之間沒有公共邊。

題目意識比較難懂,我們來分析一下第一組樣例:

..3.
023.
.211
對應可以建出來這樣的效果:
.X.Y
0...
..11
那麼對應有4種建築,輸出4.


思路:

1、首先如果我們沒有這些古代建築,只是一個N*M的一個矩陣的話,我們按照點的座標的奇偶性((x+y)%2)將矩陣分成一個二分圖,然後將每個點與其周圍四個點(有公共邊)建立一條無向邊,表示這兩個點如果在一起建立是矛盾的。

那麼不難理解:我們現在跑一遍匈牙利演算法求得的最大二分匹配數==最小點覆蓋數*2(因為是無向邊).那麼如果我們將屬於最小點覆蓋集的點去掉,剩下的點就是屬於最大獨立集的點,那麼此時能夠建立的最多的建築的數目:n*m-最大匹配數/2【最大獨立集=n-最大二分匹配數】

2、那麼現在引入這些古代建築,題幹中保證了這些古代建築一共只有10種(0-9),那麼我們可以暴力列舉一下哪些古代建築我們建立起來,哪些古代建築我們不建立。對應建立起來的古代建組周圍的“.”的點我們拋棄掉,建立起來的古代建築的點也拋棄掉,沒有建立起來的古代建築的點也拋棄掉。剩下的“.”,我們按照第一步的思路建二分圖,然後求最大獨立集即可。

Ac程式碼:

#include<stdio.h>
#include<string.h>
#include<vector>
using namespace std;
vector<int >mp[50*50];
int num[50][50];
int match[50*50];
int vis2[50*50];
int map[15][15];
int fx[4]={0,0,1,-1};
int fy[4]={1,-1,0,0};
char a[15][15];
int use[10];
int vis[10];
int n,m,contz,ans,contn;
int find(int u)
{
    for(int i=0;i<mp[u].size();i++)
    {
        int v=mp[u][i];
        if(vis2[v]==0)
        {
            vis2[v]=1;
            if(match[v]==-1||find(match[v]))
            {
                match[v]=u;
                return 1;
            }
        }
    }
    return 0;
}
void Slove()
{
    int output=0;
    memset(match,-1,sizeof(match));
    for(int i=1;i<=contn;i++)
    {
        memset(vis2,0,sizeof(vis2));
        if(find(i)==1)output++;
    }
    int sum=0;
    for(int i=0;i<contz;i++)if(vis[i]==1)sum++;
    ans=max(ans,sum+contn-output/2);
}
void Getmap()
{
    memset(map,0,sizeof(map));
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            if(a[i][j]=='.')
            {
                for(int k=0;k<4;k++)
                {
                    int x=i+fx[k];
                    int y=j+fy[k];
                    if(x>=0&&x<n&&y>=0&&y<m&&a[x][y]!='.')
                    {
                        if(vis[a[x][y]-'0']==1)
                        {
                            map[i][j]=1;
                        }
                    }
                }
                continue;
            }
            else
            {
                map[i][j]=1;
                for(int k=0;k<4;k++)
                {
                    int x=i+fx[k];
                    int y=j+fy[k];
                    if(x>=0&&x<n&&y>=0&&y<m)
                    {
                        if(vis[a[i][j]-'0']==1&&vis[a[x][y]-'0']==1&&a[i][j]!=a[x][y])
                        {
                            return ;
                        }
                    }
                }
            }
        }
    }
    for(int i=1;i<=n*m;i++)mp[i].clear();
    contn=0;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            if(map[i][j]==0)
            {
                num[i][j]=++contn;
            }
        }
    }
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            if(map[i][j]==0)
            {
                for(int k=0;k<4;k++)
                {
                    int x=i+fx[k];
                    int y=j+fy[k];
                    if(x>=0&&x<n&&y>=0&&y<m&&map[x][y]==0)
                    {
                        mp[num[i][j]].push_back(num[x][y]);
                    }
                }
            }
        }
    }
    Slove();
}
void Dfs(int now)
{
    if(now==contz)
    {
        Getmap();
        return ;
    }
    vis[now]=1;
    Dfs(now+1);
    vis[now]=0;
    Dfs(now+1);
}
int main()
{
    int t;
    int kase=0;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        for(int i=0;i<n;i++)
        {
            scanf("%s",a[i]);
        }
        memset(use,-1,sizeof(use));
        contz=0;
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<m;j++)
            {
                if(a[i][j]=='.')continue;
                if(use[a[i][j]-'0']==-1)
                {
                    use[a[i][j]-'0']=contz++;
                    a[i][j]=use[a[i][j]-'0']+'0';
                }
                else
                {
                    a[i][j]=use[a[i][j]-'0']+'0';
                }
            }
        }
        ans=0;
        Dfs(0);
        printf("Case #%d: %d\n",++kase,ans);
    }
}