http://www.cnblogs.com/live-no-regrets/

HDU1281 二分图最大匹配 匈牙利算法

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

 

 题解:和前面写过的一个二分匹配题类似,同样通过相当于对x,y缩点,这里缩点后其实就是行编号和列编号,
  若有一个点可以放棋子,那么在这个点对应的行编号和列编号之间连边,因此产生一个二分图,所求答案就是这个二分图最大匹配。(匈牙利法)
  最主要的是把这个问题想成二分图很神奇,并不是把一个格子想成一点,而是把行标和列标想成一点。
  此题还需要求重要点,那么可以对二分图中每一条边(其实就是所给的能放棋子的点)删掉再求最大匹配,
  如果小于先前所求最大匹配,那么就是重要点。

#include<iostream>
#include<string.h>
#include<vector>
#define N 250
using namespace std;
int n,m,k,map[N][N],x[N],y[N],mat[N];
bool vis[N];
bool find(int x)
{
    for (int i=1;i<=n+m;i++){
        if (map[x][i]){
            if (vis[i])continue;
            vis[i]=true;
            if (!mat[i]||find(mat[i])){
                mat[i]=x,mat[x]=i;
                return true;
            }
        }
    }
    return false;
}
int hungarian()
{
    int sum=0,i;
    memset(mat,0,sizeof(mat));
    for (i=1;i<=n+m;i++)
        if (!mat[i]){
            memset(vis,false,sizeof(vis));
            if (find(i))sum++;
        }
    return sum;
}
int main()
{
    int id=0,i;
    while (~scanf("%d%d%d",&n,&m,&k)){
        id++;
        memset(map,0,sizeof(map));
        for (i=1;i<=k;i++){cin>>x[i]>>y[i];y[i]+=n;map[x[i]][y[i]]=map[y[i]][x[i]]=1;}
        int Max=hungarian(),ans;
        for (i=1,ans=0;i<=k;i++){
            map[x[i]][y[i]]=0;
            map[y[i]][x[i]]=0;
            int res=hungarian();
            if (res<Max)ans++;
            map[x[i]][y[i]]=map[y[i]][x[i]]=1;
        }
        printf("Board %d have %d important blanks for %d chessmen.\n",id,ans,Max);
    }
    return 0;
}

AC!

posted @ 2020-11-28 20:33  voyage~st~Imagine  阅读(72)  评论(0编辑  收藏  举报