洛谷P4304 TJOI2013 攻击装置 (二分图匹配)
题目大意:一个矩阵,一些点被拿掉,在棋盘上马走日,马之间不能落在同一点,求最多放几匹马。
采用对矩阵黑白染色,画个图可以发现:马可以走到的位置和他所处的位置颜色不同,将马和他可以走到的位置连边,最多可以放多少马,相当于求图的最大独立集(任意一条边的两个端点不会同时被选中)。
用黑白染色将节点按颜色分成两类,就是一个二分图。
题解代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define maxn 40000 4 struct edge{ 5 int to,nxt; 6 }e[maxn*8+5]; 7 bool vis[maxn+5]; 8 char Map[maxn+5][maxn+5];//存矩阵 9 int head[maxn+5]={0},link[maxn+5]; 10 int dx[9]={-1,1,-2,2,-1,1,-2,2}; 11 int dy[9]={-2,-2,-1,-1,2,2,1,1};//马走日的八个方位 12 int n,p,ans,cnt; 13 14 void add(int x,int y){//用矩阵中方格的编号建图 15 e[++cnt].nxt=head[x]; 16 head[x]=cnt; 17 e[cnt].to=y; 18 } 19 20 int Getnum(int x,int y){//得到该点编号,相当于一个矩阵从左上依次数 21 return (x-1)*n+y; 22 } 23 24 void read(){ 25 scanf("%d",&n); 26 for(int i=1;i<=n;i++) 27 for(int j=1;j<=n;j++){ 28 cin>>Map[i][j]; 29 if(Map[i][j]=='1') p++;//统计障碍数 30 } 31 for(int i=1;i<=n;i++) 32 for(int j=1;j<=n;j++) 33 if(Map[i][j]=='0'&&(i+j)%2)//用黑白染色,左上是黑,(i+j)%2表示白色 34 for(int k=0;k<8;k++){//八个方位遍历 35 int tx=i+dx[k]; 36 int ty=j+dy[k]; 37 if(tx>=1&&tx<=n&&ty>=1&&ty<=n&&Map[tx][ty]=='0'){//满足条件 38 add(Getnum(i,j),Getnum(tx,ty)); 39 } 40 } 41 42 } 43 44 bool match(int x){//标准的匈牙利算法 45 for(int i=head[x];i;i=e[i].nxt){ 46 int v=e[i].to; 47 if(!vis[v]){ 48 vis[v]=1; 49 if(!link[v]||match(link[v])){ 50 link[v]=x; 51 return true; 52 } 53 } 54 } 55 return false; 56 } 57 58 void solve(){ 59 for(int i=1;i<=n;i++) 60 for(int j=1;j<=n;j++) 61 if(Map[i][j]=='0'&&(i+j)%2){ 62 memset(vis,0,sizeof(vis)); 63 if(match(Getnum(i,j))) ans++; 64 } 65 cout<<n*n-p-ans;//最大独立集=节点总数减去最大匹配 66 } 67 68 int main(){ 69 read(); 70 solve(); 71 return 0; 72 }