标签:ios += efi head for 国际象棋 匈牙利 fine void
题目应该就是最大独立集了吧,没什么了,平面图求最大独立集需要/2的,
WQH说加直接+双向边考研过,结果真的过了,应该是匈牙利算法寻找的
时候更加快了吧。(方便找边)
1 #include<cstdio> 2 #include<algorithm> 3 #include<cmath> 4 #include<iostream> 5 #include<cstring> 6 #define N 207 7 using namespace std; 8 9 const int lx[8]={1,2,2,1,-1,-2,-2,-1}; 10 const int ly[8]={2,1,-1,-2,-2,-1,1,2}; 11 12 int n,m; 13 int a[N][N],mark[N][N],du[N*N]; 14 int cnt,head[N*N],next[N*N*N],rea[N*N*N]; 15 int dui[N*N],flag[N*N]; 16 17 void add(int u,int v){next[++cnt]=head[u],head[u]=cnt,rea[cnt]=v;} 18 bool dfs(int u) 19 { 20 for (int i=head[u];i!=-1;i=next[i]) 21 { 22 int v=rea[i]; 23 if (flag[v]) continue; 24 flag[v]=1; 25 if (!dui[v]||dfs(dui[v])) 26 { 27 dui[v]=u; 28 return 1; 29 } 30 } 31 return 0; 32 } 33 int main() 34 { 35 memset(head,-1,sizeof(head)); 36 scanf("%d%d",&n,&m); 37 int num=0; 38 for (int i=1;i<=n;i++) 39 for (int j=1;j<=m;j++) 40 { 41 scanf("%d",&a[i][j]); 42 mark[i][j]=(i-1)*m+j; 43 if (a[i][j]) num++; 44 } 45 int x,y; 46 for (int i=1;i<=n;i++) 47 for (int j=1;j<=m;j++) 48 if (a[i][j]==0) 49 for (int k=0;k<8;k++) 50 { 51 x=i+lx[k],y=j+ly[k]; 52 if(a[x][y]) continue; 53 if (x<=n&&x>=1&&y>=1&&y<=m) add(mark[i][j],mark[x][y]),add(mark[x][y],mark[i][j]); 54 } 55 memset(dui,0,sizeof(dui)); 56 int ans=0; 57 for (int i=1;i<=n;i++) 58 for (int j=1;j<=m;j++) 59 if (a[i][j]==0) 60 { 61 memset(flag,0,sizeof(flag)); 62 ans+=dfs(mark[i][j]); 63 } 64 ans=n*m-num-ans/2; 65 printf("%d",ans); 66 }
其实还有更优秀的思想
(图太丑,不管了)
这里可以,将平面图分成这样的格点图,玩过国际象棋的都知道,马是一黑一白交替着走的,
也就说,在同种颜色中,马不会相互攻击,那只需要计算一种颜色中最大独立集就可以了,
这样就是先记录可以填的位置,然后只需要操作一种颜色,连边出去,连向另外一个集合,
这样匹配的就是无法共存点,这样就OK了。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 #define hash(A,B) ((A)*m-m+B) 6 #define ok(A,B) (A>=1&&A<=n&&B>=1&&B<=m&&!mp[A][B]) 7 #define N 40010 8 #define M 500010 9 10 int m,n,flow,sum; 11 int cnt,head[N],vis[N],match[N],mp[250][250]; 12 struct Edge{int to,nxt;}e[M]; 13 int dis[8][2]={{-1,2},{-1,-2},{1,2},{1,-2},{-2,1},{-2,-1},{2,1},{2,-1}}; 14 15 void adde(int u,int v) 16 { 17 e[++cnt].to=v; 18 e[cnt].nxt=head[u]; 19 head[u]=cnt; 20 } 21 bool dfs(int u,int flag) 22 { 23 for(int i=head[u];~i;i=e[i].nxt) 24 { 25 int v=e[i].to; 26 if(vis[v]==flag) continue; 27 vis[v]=flag; 28 if(!match[v]||dfs(match[v],flag)) 29 { 30 match[v]=u; 31 return 1; 32 } 33 } 34 return 0; 35 } 36 int main() 37 { 38 cnt=0;sum=0;flow=0; 39 memset(head,-1,sizeof(head)); 40 scanf("%d%d",&n,&m); 41 for(int i=1;i<=n;++i) 42 for(int j=1;j<=m;++j) scanf("%d",&mp[i][j]); 43 for(int i=1;i<=n;++i) 44 for(int j=1;j<=m;++j) 45 { 46 if(mp[i][j]) continue;sum++; 47 if((i^j)&1) 48 { 49 for(int k=0;k<8;++k) 50 if(ok(i+dis[k][0],j+dis[k][1])) 51 { 52 adde(hash(i,j),hash(i+dis[k][0],j+dis[k][1])); 53 } 54 } 55 } 56 for(int i=1;i<=n;++i) 57 for(int j=1;j<=m;++j) 58 { 59 if(mp[i][j]) continue; 60 if((i^j)&1) 61 { 62 int p=hash(i,j); 63 if(dfs(p,p)) flow++; 64 } 65 } 66 printf("%d\n",sum-flow); 67 return 0; 68 }
标签:ios += efi head for 国际象棋 匈牙利 fine void
原文地址:http://www.cnblogs.com/fengzhiyuan/p/7654375.html