BZOJ 2150 部落战争 (二分图匹配)
题目大意:给你一个n*m的棋盘,有一些坏点不能走,你有很多军队,每支军队可以像象棋里的马一样移动,不过马是1*2移动的,而军队是r*c移动的,军队只能从上往下移动,如果一个点已经被一直军队经过,那么其他军队不能再经过这个点,求覆盖所有非坏点的最少军队数
对在某个点的军队可能跳的位置建边。把图抠出来,因为军队只能从上往下移动,所以他移动的方式就是是一条链,所以答案就是把这个图分成若干条链,求链的数量的最小值
这不就是二分图匹配么
对于一个链,除了端点,每个点都需要一个出边一个入边,跑匈牙利就行了
注意,每个点跑匈牙利之前都要清一次vis数组!才能正确表示某个点在这次匹配中是否已经被使用
1 #include <queue> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #define N 60 6 #define mod 20100403 7 #define p(i,j) ((i-1)*m+j) 8 #define dd double 9 using namespace std; 10 11 char str[N][N]; 12 int n,m,r,c,cte; 13 int mp[N][N],head[N*N],vis[N*N],mch[N*N]; 14 int xx[4],yy[4]; 15 struct Edge{int to,nxt;}edge[N*N*10]; 16 void ae(int u,int v){ 17 ++cte,edge[cte].to=v; 18 edge[cte].nxt=head[u]; 19 head[u]=cte; 20 } 21 int check(int x,int y){ 22 if(x<1||y<1||x>n||y>m||mp[x][y]) return 0; 23 return 1; 24 } 25 void build_edge() 26 { 27 for(int i=1;i<=n;i++) 28 for(int j=1;j<=m;j++) 29 { 30 if(mp[i][j]) continue; 31 for(int k=0;k<4;k++) 32 if(check(i+xx[k],j+yy[k])) 33 ae(p(i,j),p(i+xx[k],j+yy[k])); 34 } 35 } 36 int Hungary(int x) 37 { 38 for(int j=head[x];j!=-1;j=edge[j].nxt){ 39 int v=edge[j].to; 40 if(!vis[v]) 41 { 42 vis[v]=1; 43 if(!mch[v]||Hungary(mch[v])){ 44 mch[v]=x; 45 return 1; 46 } 47 } 48 }return 0; 49 } 50 51 52 int main() 53 { 54 scanf("%d%d%d%d",&n,&m,&r,&c); 55 for(int i=1;i<=n;i++){ 56 scanf("%s",str[i]+1); 57 for(int j=1;j<=m;j++) 58 if(str[i][j]=='.') mp[i][j]=0; 59 else mp[i][j]=1; 60 } 61 xx[0]=r,xx[1]=r,xx[2]=c,xx[3]=c; 62 yy[0]=c,yy[1]=-c,yy[2]=r,yy[3]=-r; 63 int ans=0; 64 memset(head,-1,sizeof(head)); 65 build_edge(); 66 for(int i=1;i<=n;i++) 67 for(int j=1;j<=m;j++){ 68 if(mp[i][j]) continue; 69 memset(vis,0,sizeof(vis)); 70 if(!Hungary(p(i,j))) ans++;} 71 printf("%d\n",ans); 72 return 0; 73 }