hdoj 5556 Land of Farms 【DFS + 最大独立集->补图最大团】



Land of Farms

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


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×M grids. 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 ( T200 ).

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 ( 1N,M10 ). 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
 



1A好激动啊!


题意:给定n*m的格子,上面只有字符'.' 和 数字0-9。其中数字表示这是该格是古老的土地,字符'.'表示该格只是普通的土地。可以认为一块古老的农田由相邻的所有数字相同的格组成的块,一块普通的农田只由一格组成。现在要建立最大数目的农田,要求任意两块农田不能相邻。问你能够建立的最大数目。


语文不好啊。。。


比如说  

1111

1..1

1991

1111

其中

1111

1  1

1  1

1111 为一块古老的农田,   99为一块古老的农田 .为一块普通的农田 

一共有4块农田(有两个 . )可供选择,因为选择的农田不能相邻,所以我们最多选择两个。



思路:把所有古老的农田和普通的农田用一个点表示,这里可用DFS实现。然后根据对立关系建图。最后就是求解最大独立集,而最大独立集  = 补图的最大团 = 节点数 - 最大匹配数。


我用的最大团写的。



AC代码:


#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <vector>
#define INF 0x3f3f3f3f
#define eps 1e-4
#define MAXN (100+10)
#define MAXM (1000000)
#define Ri(a) scanf("%d", &a)
#define Rl(a) scanf("%lld", &a)
#define Rf(a) scanf("%lf", &a)
#define Rs(a) scanf("%s", a)
#define Pi(a) printf("%d\n", (a))
#define Pf(a) printf("%lf\n", (a))
#define Pl(a) printf("%lld\n", (a))
#define Ps(a) printf("%s\n", (a))
#define W(a) while(a--)
#define CLR(a, b) memset(a, (b), sizeof(a))
#define MOD 100000007
#define LL long long
#define lson o<<1, l, mid
#define rson o<<1|1, mid+1, r
#define ll o<<1
#define rr o<<1|1
using namespace std;
char str[15][15];
int Map[MAXN][MAXN];
int Clique[MAXN];
int New[MAXN][MAXN];
int used[MAXN];
int ans;
int N;
int DFS(int T, int cnt)
{
    if(T == 0)
    {
        if(ans < cnt)
        {
            ans = cnt;
            return 1;
        }
        return 0;
    }
    for(int i = 0; i < T; i++)
    {
        if(T - i + cnt <= ans) return 0;
        int u = New[cnt][i];
        if(Clique[u] + cnt <= ans) return 0;
        int num = 0;
        for(int j = i+1; j < T; j++)
            if(Map[u][New[cnt][j]] == 0)
                New[cnt+1][num++] = New[cnt][j];
        used[cnt+1] = u;
        if(DFS(num, cnt+1)) return 1;
    }
    return 0;
}
int MaxClique()
{
    memset(Clique, 0, sizeof(Clique));
    ans = 0;
    for(int i = N; i >= 1; i--)
    {
        used[1] = i; int Size = 0;
        for(int j = i+1; j <= N; j++)
            if(Map[i][j] == 0)
                New[1][Size++] = j;
        DFS(Size, 1);
        Clique[i] = ans;
    }
    return ans;
}
int n, m;
bool judge(int x, int y){
    return x >= 0 && x < n && y >= 0 && y < m;
}
bool number(char c){
    return c >= '0' && c <= '9';
}
int getpoint(int x, int y){
    return x * m + y + 1;
}
int num[15][15];
bool vis[15][15];
int Move[4][2] = {1,0, 0,1, -1,0, 0,-1};
void Name(int x, int y)
{
    num[x][y] = N; vis[x][y] = true;
    for(int k = 0; k < 4; k++)
    {
        int next_x = x + Move[k][0];
        int next_y = y + Move[k][1];
        if(vis[next_x][next_y] || !judge(next_x, next_y))
            continue;
        if(str[next_x][next_y] == str[x][y])
            Name(next_x, next_y);
    }
}
void getMap()
{
    Ri(n); Ri(m);
    N = 0;
    for(int i = 0; i < n; i++)
        Rs(str[i]);
    CLR(Map, 0); CLR(vis, false);
    for(int i = 0; i < n; i++)
    {
        for(int j = 0; j < m; j++)
        {
            if(number(str[i][j]))
            {
                if(vis[i][j]) continue;
                num[i][j] = ++N;
                Name(i, j);
            }
            else
                num[i][j] = ++N;
        }
    }
    for(int i = 0; i < n; i++)
    {
        for(int j = 0; j < m; j++)
        {
            for(int k = 0; k < 4; k++)
            {
                int x = i + Move[k][0];
                int y = j + Move[k][1];
                if(!judge(x, y)) continue;
                if(number(str[x][y]) && number(str[i][j]) && str[i][j] != str[x][y])
                    Map[num[x][y]][num[i][j]] = 1;
                else if(str[x][y] == '.' && str[i][j] == '.')
                    Map[num[x][y]][num[i][j]] = 1;
                else if(number(str[x][y]) && !number(str[i][j]) || !number(str[i][j]) && number(str[x][y]))
                    Map[num[x][y]][num[i][j]] = 1;
            }
        }
    }
}
int main()
{
    int t, kcase = 1; Ri(t);
    W(t)
    {
        getMap();
        printf("Case #%d: %d\n", kcase++, MaxClique());
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值