Description
给 定一个01矩阵,其中你可以在0的位置放置攻击装置。每一个攻击装置(x,y)都可以按照“日”字攻击其周围的 8个位置(x-1,y-2),(x-2,y-1),(x+1,y-2),(x+2,y-1),(x-1,y+2),(x-2,y+1), (x+1,y+2),(x+2,y+1)
求在装置互不攻击的情况下,最多可以放置多少个装置。
Input
第一行一个整数N,表示矩阵大小为N*N。接下来N行每一行一个长度N的01串,表示矩阵。
Output
一个整数,表示在装置互不攻击的情况下最多可以放置多少个装置。
Sample Input
3
010
000
100
Sample Output
4
HINT
100%数据 N<=200
正解:二分图最大匹配(匈牙利算法)
解题报告:
显然,被某个点走到的点都不能与它共存,不妨给他们连边,然后求一个二分图最大独立子集。
二分图最大独立子集就是等于总点数减去匹配数。因为每一次匹配完之后,就会多一条边,意味着边连接的两个点只能选一个,所以就少了一个。
有所优化的就在于不用memset数组,直接给访问数组一个每次dfs特有的标记即可。
1 //It is made by jump~ 2 #include <iostream> 3 #include <cstdlib> 4 #include <cstring> 5 #include <cstdio> 6 #include <cmath> 7 #include <algorithm> 8 #include <ctime> 9 #include <vector> 10 #include <queue> 11 #include <map> 12 #include <set> 13 #ifdef WIN32 14 #define OT "%I64d" 15 #else 16 #define OT "%lld" 17 #endif 18 using namespace std; 19 typedef long long LL; 20 const int MAXM = 1000011; 21 const int MAXN = 211; 22 int n,ecnt; 23 int yi[4][2]={{1,-2},{2,-1},{1,2},{2,1}};//只处理往右的 24 int first[MAXN*MAXN],to[MAXM],next[MAXM]; 25 int a[MAXN][MAXN]; 26 int vis[40011]; 27 int match[MAXN*MAXN],jilu; 28 int ans,flag,tot; 29 30 inline int getint() 31 { 32 int w=0,q=0; 33 char c=getchar(); 34 while((c<‘0‘ || c>‘9‘) && c!=‘-‘) c=getchar(); 35 if (c==‘-‘) q=1, c=getchar(); 36 while (c>=‘0‘ && c<=‘9‘) w=w*10+c-‘0‘, c=getchar(); 37 return q ? -w : w; 38 } 39 40 inline void link(int x,int y){ 41 next[++ecnt]=first[x]; first[x]=ecnt; to[ecnt]=y; 42 next[++ecnt]=first[y]; first[y]=ecnt; to[ecnt]=x; 43 } 44 45 inline bool dfs(int x){ 46 for(int i=first[x];i;i=next[i]) { 47 int v=to[i]; if(vis[v]==jilu) continue; 48 vis[v]=jilu; 49 if(!match[v] || dfs(match[v])) { 50 match[v]=x; //match[x]=v;//需要记两次就不需要两边记录了 51 return true; 52 } 53 } 54 return false; 55 } 56 57 inline void work(){ 58 n=getint(); char c; 59 for(int i=1;i<=n;i++) 60 for(int j=1;j<=n;j++){ 61 c=getchar(); 62 while(c!=‘0‘ && c!=‘1‘) c=getchar(); 63 if(c==‘1‘) continue; 64 else tot++; 65 a[i][j]=tot; 66 } 67 int x,y; 68 for(int i=1;i<=n;i++) 69 for(int j=1;j<=n;j++) { 70 if(!a[i][j]) continue; 71 for(int k=0;k<=3;k++) { 72 x=i+yi[k][0]; y=j+yi[k][1]; 73 if(x<=0 || y<=0 || x>n || y>n) continue; 74 if(!a[x][y]) continue; 75 link(a[x][y],a[i][j]); 76 } 77 } 78 ans=0;//注意初值 79 for(int i=1;i<=tot;i++) { 80 jilu++;//不用清空,打一个标记即可 81 if( dfs(i) ) ans++;//显然冲突的地方只能放一个 82 } 83 //点数减去最大匹配数即最大独立集 84 printf("%d\n",tot-ans/2); 85 } 86 87 int main() 88 { 89 work(); 90 return 0; 91 }
时间: 2024-10-03 14:24:21