清华大学算法训练营——程序九:象棋

描述

你有足够多的象棋“车”,在一个n×n的棋盘上你能放多少个“车”呢?注意,所给棋盘上有些位置不能放任何东西。同时,某一行(列)最多只能存在一个“车”。

输入

第一行为一个正整数n。(1<=n<=500 )

接下来n行,每行包含n个整数,若为0表示这个位置不能放“车”;若为1表示这个位置可以放“车”。

输出

输出一个整数,表示最多能放多少个“车”。

样例输入

5
1 0 0 0 0
0 0 0 0 0
0 0 0 1 0
1 1 0 1 0
0 0 0 1 0

样例输出

3

样例解释

将行看作X集合,列看作Y集合

若棋盘上为1的位置有(i,j),则X集的第i个点向Y集的第j个点连边

#include <bits/stdc++.h>
using namespace std;

const int N = 505*2, M= N * N;
struct E{
    //next:下一条邻接边
    //to:本条边所指向的终点
    int next,to;
}e[M];
//ihead:邻接表的头
//cnt:邻接表大小 
//mc:表示每个点所匹配到的另一个点match
//vis:Y集元素是否被访问过
int cnt,ihead[N],mc[N];
bool vis[N];
//邻接表连边,表示连一条x到y的有向边
//x:起点
//y:终点
void add(int x,int y){
    ++cnt;
    e[cnt].next = ihead[x];
    e[cnt].to = y;
    ihead[x] = cnt;
}
//匈牙利算法
//x:x集上的点,从当前点出发找增广路
//返回值:若找到增广路则返回true,否则返回false
bool dfs(int x){
    for(int i=ihead[x]; i!=0; i=e[i].next){
        int y = e[i].to;
        if(!vis[y]){//如果找到一个Y集上的点没有标记
            vis[y] = true;//标记该点
            //如果y是没有匹配点的,说明找到了一条增广路;或者说递归查找y的匹配点,得到了一条增广路
            if(mc[y] == 0 || dfs(mc[y])){
                //找到了增广路,更新mc数组
                mc[x] = y;
                mc[y] = x;
                return true;
            }
        }
    }
    return false;
}
// 求解棋盘上最多能放多少个“车”
// n:棋盘的大小为n×n的
// board:所给棋盘,对于某个位置上的数:若值为1表示可以放“车”;若值为0表示不能放“车”
// 返回值:能放“车”的最大个数
int getAnswer( int n, vector<vector<int>> board) {
//将行看作n个点,将列看作另外n个点,标号分别是1到n和n+1到2n
   cnt = 0;
   for(int i=1; i <= n * 2; ++i){
        ihead[i] = 0;
        mc[i] = 0;
   }
   //连边
   for(int i = 1; i <= n; ++i)
     for(int j = 1; j <= n; ++j)
        if(board[i-1][j-1] == 1)
            add(i,j+n);
   int ans = 0;
   for(int i=1; i<=n; ++i)
      if(!mc[i]){
        //如果x集中的第i个点没有匹配到Y集上的点,则从这个点出发寻找增广路
        memset(vis, 0, sizeof(bool) * (n * 2 + 1));
        //将数组置为0
        if(dfs(i))
            ++ans;//如果找到,答案直接+1
      }
   return ans;
}

int main() {
    int n;
    scanf("%d", &n);
    vector<vector<int>> e;
    for (int i = 0; i < n; ++i) {
        vector<int> t;
        for (int j = 0; j < n; ++j) {
            int x;
            scanf("%d", &x);
            t.push_back(x);
        }
        e.push_back(t);
    }
    printf("%d\n", getAnswer(n, e));
    return 0;
}

猜你喜欢

转载自blog.csdn.net/zhaohaibo_/article/details/81455868