【传送门:BZOJ2150】
简要题意:
给出一个矩阵,矩阵上的字符有两种,一种是'x',表示山洞(不可走),一种是'.',表示城镇
可以在城镇处放士兵,士兵经过的每个城镇都会被占领,士兵只能向下走,而且行走的方式和马相似,不过马走的是1*2,士兵走的是R*C,士兵不能经过一个被占领的城镇
求出最少派出多少个士兵能够占领所有城镇
题解:
最小路径覆盖问题,用二分图匹配
将所有城镇拆成两个集合
如果x能走到y,则x连向y的第二个集合的点
然后将总点数-最大匹配数就是最小路径覆盖数了
参考代码:
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<cstdlib> using namespace std; char st[51][51]; struct node {int x,y,next; }a[21000];int len,last[6100]; void ins(int x,int y) {len++;a[len].x=x;a[len].y=y;a[len].next=last[x];last[x]=len; } int dx[5],dy[5]; int n,m,r,c; int p(int x,int y){return (x-1)*m+y;} int match[6100],chw[6100]; bool findmuniu(int x,int t) {for(int k=last[x];k;k=a[k].next){int y=a[k].y;if(chw[y]!=t){chw[y]=t;if(match[y]==0||findmuniu(match[y],t)==true){match[y]=x;return true;}}}return false; } int main() {scanf("%d%d%d%d",&n,&m,&r,&c);for(int i=1;i<=n;i++) scanf("%s",st[i]+1);len=0;memset(last,0,sizeof(last));dx[1]=r;dy[1]=-c;dx[2]=r;dy[2]=c;dx[3]=c;dy[3]=-r;dx[4]=c;dy[4]=r;int sum=0;for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){if(st[i][j]=='.'){sum++;for(int k=1;k<=4;k++){int tx=i+dx[k],ty=j+dy[k];if(tx<1||ty<1||tx>n||ty>m||st[tx][ty]=='x') continue;ins(p(i,j),p(tx,ty)+n*m);}}}}memset(chw,0,sizeof(chw));memset(match,0,sizeof(match));for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){if(st[i][j]=='.'){int t=p(i,j);if(findmuniu(t,t)==true) sum--;}}}printf("%d\n",sum);return 0; }