Problem Description
给定一个n * m的棋盘,在棋盘里放尽量多的国际象棋中的车,使他们不能相互攻击 已知有些格子不能放置,问最多能放置多少个车 并计算出必须棋盘上的必须点。
Input
第一行有三个数N、M、K(1<N,M<=100 1<K<=N*M),表示了棋盘的高、宽,以及可以放“车”的格子数目。接下来的K行描述了所有格子的信息:每行两个数X和Y,表示了这个格子在棋盘中的位置。
output
对输入的每组数据,按照如下格式输出:
Board T have C important blanks for L chessmen.
思路:对于第一个问题 可以把行、列看做二分图的左右节点,共n + m个节点 对所有可放置车的坐标(x, y) 把x,y连边 然后放一个车相当于将x, y两节点匹配 然后就可以用二分图最大匹配来做了
对于第二个问题,暴力枚举所有(x,y),并将其挖掉,如果匹配数减少了,(x,y)就是必须点。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int N = 11000; int n, m, q, mat[220]; bool vis[220], f[220][220]; int head[220],now; struct edges{ int to,next; }edge[N<<2]; void add(int u,int v){ edge[++now] = {v,head[u]}; head[u] = now;} struct input{ int x,y; }inp[N]; void init(){ memset(edge,0,sizeof(edge)); memset(head,0,sizeof(head)); now = 0; memset(mat,0,sizeof(mat)); } bool dfs(int x){ for(int i = head[x]; i; i = edge[i].next){ int v = edge[i].to; if(!vis[v] && !f[x][v]){ vis[v] = 1; if(!mat[v] || dfs(mat[v])){ mat[v] = x; return 1; } } } return 0; } int main(){ // freopen("data.in","r",stdin); ios::sync_with_stdio(false); int kase = 0; while(cin>>n>>m>>q){ init(); int x,y; for(int i = 1; i <= q; i++){ cin>>x>>y; y += n; inp[i] = {x, y}; add(x,y);// add(y,x); } int ans = 0; for(int i = 1; i <= n; i++){ memset(vis,0,sizeof(vis)); if(dfs(i)) ans++; } int tot = 0; for(int i = 1; i <= q; i++){ f[inp[i].x][inp[i].y] = f[inp[i].y][inp[i].x] = 1; //枚举每个可放置的点 memset(mat,0,sizeof(mat)); int cnt = 0; //cnt记录每次挖去一个点后的匹配数 for(int j = 1; j <= n; j++){ memset(vis,0,sizeof(vis)); if(dfs(j)) cnt++; } if(cnt < ans) tot++; f[inp[i].x][inp[i].y] = 0; } printf("Board %d have %d important blanks for %d chessmen.\n",++kase,tot,ans); } return 0; }