大意:

对一个N*M的棋盘,在格子里放尽量多的一些国际象棋里面的“车”,并且使得他们不能互相攻击,这当然很简单,但是Gardon限制了只有某些格子才可以放,小希还是很轻松的解决了这个问题(见下图)注意不能放车的地方不影响车的互相攻击。 
所以现在Gardon想让小希来解决一个更难的问题,在保证尽量多的“车”的前提下,棋盘里有些格子是可以避开的,也就是说,不在这些格子上放车,也可以保证尽量多的“车”被放下。但是某些格子若不放子,就无法保证放尽量多的“车”,这样的格子被称做重要点。Gardon想让小希算出有多少个这样的重要点,你能解决这个问题么?

 

思路:

1、首先我们考虑以X,Y轴为节点连边,这样的话,就可以保证一个“车”可以统治它所在的列和行了。为什么可以这样呢?因为由二分图的性质可知,没有两条边是依附于一个顶点,自己画画图就可以知道以X,Y轴为节点连边刚好满足条件。

2、求得二分匹配之后我们怎样操作?根据关键点的定义我们可以想到,再求第一次二分匹配之后,我们将已经匹配的点存起来,然后我们通过枚举的方式将这些边删除之后求二分匹配,这样我们就可以得到以前的点是不是关键点了。

3、注意这里数据范围是100*100,我想了想,如果数据范围还大一些的话,用邻接表存储是十分麻烦的,因为删除边的操作比较麻烦,于是我用邻接矩阵去实现的。

另外:一个小错误导致我想了一天多的时间才写出来。

CODE:

 

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define MAXN 110
#define MAXM 40010 

struct Edge
{
    int u, v;
}a[MAXN]; //存储第一次最大匹配过后的饱和点 

int G[MAXN][MAXN];
int n, m, k;
int cnt;

int first[MAXN], link[MAXN];
bool vis[MAXN];

void init()
{
    memset(G, 0sizeof(G));
    memset(a, 0sizeof(a));
}

bool ED(int u)
{
    for(int v = 1;  v <= n; v++) if(G[u][v])
    {
        if(!vis[v])
        {
            vis[v] = 1;
            if(link[v] == -1 || ED(link[v]))
            {
                link[v] = u;
                return true;
            }
        }
    }
    return false;
}

void solve()
{
    int tot = 0;
    int ans = 0, IMpoint = 0;
    memset(link, -1sizeof(link));
    for(int i = 1; i <= n; i++)
    {
        memset(vis, 0sizeof(vis));
        if(ED(i)) ans++;
    }
    for(int i = 1; i <= n; i++) if(link[i] != -1//由匈牙利算法可知
    {
        a[tot].u = link[i], a[tot++].v = i;
    }
    for(int i = 0; i < tot; i++)
    {
        int cnt = 0;
        memset(link, -1sizeof(link));
        G[a[i].u][a[i].v] = 0//去边 
        for(int j = 1; j <= n; j++)
        {
            memset(vis, 0sizeof(vis));
            if(ED(j)) cnt++; // 写成ED(i),导致我想了一天多啊。 
        }
        if(cnt < ans) IMpoint++;
        G[a[i].u][a[i].v] = 1//恢复
    }
    printf("%d important blanks for %d chessmen.\n", IMpoint, ans);
}

int main()
{
    int times = 0;
    while(~scanf("%d%d%d", &n, &m, &k))
    {
        init();
        while(k--)
        {
            int u, v;
            scanf("%d%d", &u, &v);
            G[u][v] = 1;
        }
        printf("Board %d have ", ++times);
        solve();
    }
    return 0;
}

 

 

posted on 2012-11-07 22:41  有间博客  阅读(266)  评论(0编辑  收藏  举报