BZOJ 4808 马 二分图最大独立集

题目应该就是最大独立集了吧,没什么了,平面图求最大独立集需要/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 }

 

posted @ 2017-10-12 07:37  Kaiser-  阅读(280)  评论(0编辑  收藏  举报