zoukankan      html  css  js  c++  java
  • 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.
    ",t++,ans,ans1);
        }
        return 0;
    }
  • 相关阅读:
    内核初始化. Part 4【转】
    fixmap addresses原理【转】
    linux内核调试项【转】
    Linux Suspend流程分析【转】
    Linux电源管理-Suspend/Resume流程【转】
    Linux驱动开发常用调试工具---之内存读写工具devmem和devkmem【转】
    内核regmap机制【转】
    ARM NVIC控制器(基于cortex-M4)【转】
    Linux设备树语法详解-中断【转】
    [Go] 第一个单词首字母变大写:Ucfirst(),第一个单词首字母变小写:Lcfirst()
  • 原文地址:https://www.cnblogs.com/GoldenFingers/p/9107217.html
Copyright © 2011-2022 走看看