poj 3041 Asteroids 点覆盖(匹配)
在一个n*n网格上有一些小行星,一发子弹可以摧毁一行或一列的小行星,问最少需要多少发子弹可以摧毁全部小行星。
建立行与列的二分图,若第 i 行第 j 列有小行星则在 xi 与 yj 间连一条边,对于每一条边的两个顶点必须至少有一个被选择,即最小点覆盖, 由konig定理,点覆盖数等于匹配数,所以用匈牙利算法即可。
#include <stdio.h> #include <string.h> #define N 500 int g[N][N],mk[N],cx[N],cy[N]; int ans,n; int path(int u) { int i; for(i=1;i<=n;i++) { if(g[u][i]&&!mk[i]) { mk[i]=1; if(cy[i]==-1||path(cy[i])) { cx[u]=i; cy[i]=u; return 1; } } } return 0; } void solve() { int i; memset(cx,-1,sizeof(cx)); memset(cy,-1,sizeof(cy)); for(i=1;i<=n;i++) if(cx[i]==-1) { memset(mk,0,sizeof(mk)); ans+=path(i); } } int main() { int i,x,y,k; while(scanf("%d%d",&n,&k)!=EOF) { ans=0; memset(g,0,sizeof(g)); for(i=1;i<=k;i++) { scanf("%d%d",&x,&y); g[x][y]=1; } solve(); printf("%d\n",ans); } return 0; }