【解题报告】棋盘游戏(二分图匹配入门题)
小希和Gardon在玩一个游戏:对一个NM的棋盘,在格子里放尽量多的一些国际象棋里面的“车”,并且使得他们不能互相攻击,这当然很简单,但是Gardon限制了只有某些格子才可以放,小希还是很轻松的解决了这个问题(见下图)注意不能放车的地方不影响车的互相攻击。
所以现在Gardon想让小希来解决一个更难的问题,在保证尽量多的“车”的前提下,棋盘里有些格子是可以避开的,也就是说,不在这些格子上放车,也可以保证尽量多的“车”被放下。但是某些格子若不放子,就无法保证放尽量多的“车”,这样的格子被称做重要点。Gardon想让小希算出有多少个这样的重要点,你能解决这个问题么?
输入包含多组数据
第一行有三个数N、M、K(1<N,M<=100 1<K<=NM),表示了棋盘的高、宽,以及可以放“车”的格子数目。接下来的K行描述了所有格子的信息:每行两个数X和Y,表示了这个格子在棋盘中的位置。
样例输入
3 3 4
1 2
1 3
2 1
3 2
样例输出
Board 2 have 3 important blanks for 3 chessmen.
题意似乎有点绕,我也读了很久,来个简明扼要的:
给你一个棋盘,再给定一些格子的坐标,只有这些格子上能放棋子.求:
①最多可以往给定的格子里面放多少个车;
②对于给定的格子中的一个格子,如果我们禁止往这个格子里放车之后,①中求得的答案会发生改变,那么这个格子就叫重要点.问重要点有几个.
注:本题中认为,一个车所在的行和列上,不能有其它的车.
下面是样例的图.
画黑白空心圈圈的是给定的可以放棋子的格子
红色的圈圈表示在这里放车可以得到最多(在这道题是3个)的车
绿色的圈圈表示假如这个格子禁止放车,那么能放的最多车数将会改变(不为3)
比如,如果我们禁止往(2,1)放车,那么只有(1,2),(3,2),(1,3)可以放车,这样,我们只能得到最大放车数2,也就是往(1,3),(3,2)放车.
问题①该怎么做呢?
可以知道,对于第i行所有给定的格子,他们其中,只能有一个可以放车;同时,对于第j列中所有给定的格子,他们其中,也只能有一个可以放车;
上面这段话,说了就和没说一样.不妨画个图,把给定的格子的位置直观地表示出来:
比如"1行"到"2列"、"1行"到"3列",分别有一条边连接,表示(1,2)、(1,3)是第一行所有给定的格子的坐标.
但是,上面说过了,第一行里所有给定的格子中,只能选择一个放车.
也就是说,上面这张图里,以"1行"这个点为起点的所有边中,只能确定一条边——也就是满足“第一行里所有给定的格子中,只选择一个放车”.
上面是行的情况.列的情况也是同理:比如,以"2列"这个点为起点的所有边中,我们只能选择一条边.
稍微一想,这个图不就是二分图啊!这样综合一看,问题①就转化为了求二分图的最大匹配问题了,直接套匈牙利算法的板子,改都不带改一下的!下面是求得的最大匹配的情况:
那么如何建这个二分图呢?这是本题的难点.其实也很简单:对于每个给定的格子的坐标x和y,直接赋值mp[x][y]=1,就可以啦.
至于问题②,那就更简单了.我们只需遍历每一个给定的格子:先把这个格子抹掉(mp[i][j]←0),然后跑一遍匈牙利算法,把得到的结果与①的答案比对,如果不一样,说明这个点是符合题意的点,ans++;最后把这个格子恢复(mp[i][j]←1),就可以啦.
点击查看AC代码
#include<bits/stdc++.h>using namespace std;const int MAXN=100+5;const int MAXM=100+5;const int INF=0x3f3f3f3f;int x,y,t,tot,ans,n,m,k,cnm;int lft[MAXM];int vis[MAXN];bool mp[MAXN][MAXN];bool dfs(int i) { for(int j=1; j<=m; j++) if(!vis[j]&&mp[i][j]) { vis[j]=1; if(lft[j]==-1||dfs(lft[j])) { lft[j]=i; return 1; } } return 0;}void hungary() { memset(lft,-1,sizeof(lft)); for(int i=1; i<=n; i++) { memset(vis,0,sizeof(vis)); if(dfs(i))ans++; }}int main() { ios::sync_with_stdio(false); cin.tie(NULL); while(cin>>n>>m>>k) { t++; cnm=0; memset(mp,0,sizeof(mp)); ans=0; for(int i=1; i<=k; i++) { cin>>x>>y; mp[x][y]=1; } hungary(); tot=ans; for(int i=1; i<=n; i++) for(int j=1; j<=m; j++) { if(mp[i][j]) { mp[i][j]=0; ans=0; hungary(); mp[i][j]=1; if(ans!=tot)cnm++; } } cout<<"Board "<<t<<" have "<<cnm<<" important blanks for "<<tot<<" chessmen.\n"; } return 0;}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
2020-01-22 开始自学QT