HDU:4185-棋盘游戏

棋盘游戏
Time Limit: 2000/1000 MS (Java/Others)
Memory Limit: 65536/32768 K (Java/Others)

Problem Description

小希和Gardon在玩一个游戏:对一个N*M的棋盘,在格子里放尽量多的一些国际象棋里面的“车”,并且使得他们不能互相攻击,这当然很简单,但是Gardon限制了只有某些格子才可以放,小希还是很轻松的解决了这个问题(见下图)注意不能放车的地方不影响车的互相攻击。

所以现在Gardon想让小希来解决一个更难的问题,在保证尽量多的“车”的前提下,棋盘里有些格子是可以避开的,也就是说,不在这些格子上放车,也可以保证尽量多的“车”被放下。但是某些格子若不放子,就无法保证放尽量多的“车”,这样的格子被称做重要点。Gardon想让小希算出有多少个这样的重要点,你能解决这个问题么?

Input

输入包含多组数据,
第一行有三个数N、M、K(1

Output

对输入的每组数据,按照如下格式输出:

Board T have C important blanks for L chessmen.

Sample Input

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

Sample Output

Board 1 have 0 important blanks for 2 chessmen.
Board 2 have 3 important blanks for 3 chessmen.


解题心得:

  1. 一个二分匹配问题,把行和列单独出来,每一行中该行与可以放棋子的列形成匹配,因为每一行每一列只能放一个棋子,所以就是求一个最大二分匹配
  2. 然后就是求重要位置,刚开始还以为有什么规律,找了半天,真的找不出来,然后跑暴力,枚举每一个可以放棋子点,如果将该点去掉最大匹配变小了,那么这个点就是一个重要点了。很无语…….

#include<bits/stdc++.h>
using namespace std;
const int maxn = 110;
vector <int> ve[maxn];
int match[maxn];
bool vis[maxn],maps[maxn][maxn];
int n,m,k;

void init()
{
    memset(maps,0,sizeof(maps));
    memset(match,-1,sizeof(match));
    for(int i=0; i<maxn; i++)
        ve[i].clear();
    for(int i=1; i<=k; i++)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        maps[a][b] = true;
        ve[a].push_back(b);
    }
}

bool dfs(int x)
{
    for(int i=0; i<ve[x].size(); i++)
    {
        int v = ve[x][i];
        if(!vis[v] && maps[x][v])
        {
            vis[v] = true;
            if(match[v] == -1 || dfs(match[v]))
            {
                match[v] = x;
                return true;
            }
        }
    }
    return false;
}

int hunger()
{
    int sum_chessmen = 0;
    for(int i=1; i<=n; i++)
    {
        memset(vis,0,sizeof(vis));
        if(dfs(i))
            sum_chessmen++;
    }
    return sum_chessmen;
}

int main()
{
    int t = 1;
    while(cin>>n>>m>>k)
    {
        int ans = 0;
        init();
        int ans1 = hunger();//先跑一个原本棋盘的二分匹配
        for(int i=1;i<=n;i++)
        {
            for(int j=0;j<ve[i].size();j++)
            {
                memset(match,-1,sizeof(match));
                int y = ve[i][j];
                int x = i;
                maps[x][y] = false;//枚举去掉每一个本可以放置的点,然后判断是否二分匹配出来的答案变小了
                int ans2 = hunger();
                maps[x][y] = true;
                if(ans2 < ans1)
                    ans++;
            }
        }
        printf("Board %d have %d important blanks for %d chessmen.\n",t++,ans,ans1);
    }
    return 0;
}
posted @ 2018-01-15 20:04  GoldenFingers  阅读(102)  评论(0编辑  收藏  举报