链接:https://vjudge.net/problem/27475
题意:给定一个二维矩阵,在一些格子里放置了东西,然后你有一门炮,每次能横向或纵向开一炮,将这一行所有的东西摧毁。问你最少花多少炮弹摧毁所有的东西?并输出一组解。
题解:
很久之前做的题目了,今天在看到的时候还是很有新的体会的。这是一个求最小覆盖的问题,最小点覆盖,将行列的每个点看作是x,y集合,将放置的东西的地方看作是边(大白书)。然后求一次最大匹配,会得出来至少有多个点是不在同一行和同一列的,这样剩余的东西就会与原来的已匹配的点在同一行或者同一列,求完最大匹配后,可以得出开枪的次数,然后进行求方案数。从未匹配的点开始拓展,第一次没有参与匹配的点 在哪一行最多 或者在哪一列最多 那么肯定开枪位置就在这一行 或者这一列,这里的左右集合表现的很明显,因为记录 路径的缘故。
参考代码:
#include <stdio.h> #include <algorithm> #include <math.h> #include <string.h> #include <vector> #include <queue> #include <stack> #include <iostream> #define INF 0x3f3f3f3f using namespace std; const int maxn=1011; int mp[maxn][maxn]; int machl[maxn],machr[maxn],visx[maxn],visy[maxn]; int n,m,k; bool dfs(int u) { visx[u]=1; for(int i=1;i<=m;i++) if(!visy[i]&&mp[u][i]) { visy[i]=true; if(machr[i]==-1||dfs(machr[i])) { machl[u]=i;//列匹配 machr[i]=u;//行匹配 return true; } } return false; } int Maxmach() { int ans=0; memset(machl,-1,sizeof(machl)); memset(machr,-1,sizeof(machr)); for(int i=1;i<=n;i++) { memset(visy,0,sizeof(visy)); if(dfs(i)) ans++; } return ans; } int main() { //freopen("C:\\Users\\Administrator\\Desktop\\a.txt","r",stdin); int a,b; while(scanf("%d%d%d",&n,&m,&k),n+m+k) { memset(mp,0,sizeof(mp)); for(int i=0;i<k;i++) scanf("%d%d",&a,&b),mp[a][b]=1; int Ans=Maxmach(); printf("%d",Ans); //求方案数 memset(visx,0,sizeof(visx)); memset(visy,0,sizeof visy); for(int i=1;i<=n;i++) //从x中未匹配的点出发 if(machl[i]==-1) dfs(i); for(int i=1;i<=n;i++) if(!visx[i]) printf(" r%d",i); for(int i=1;i<=m;i++) if(visy[i]) printf(" c%d",i); printf("\n"); } return 0; }
时间: 2024-10-07 17:56:42