zoukankan      html  css  js  c++  java
  • 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
    ",sum-flow);
    67     return 0;
    68 }
  • 相关阅读:
    Quicksum -SilverN
    uva 140 bandwidth (好题) ——yhx
    uva 129 krypton factors ——yhx
    uva 524 prime ring problem——yhx
    uva 10976 fractions again(水题)——yhx
    uva 11059 maximum product(水题)——yhx
    uva 725 division(水题)——yhx
    uva 11853 paintball(好题)——yhx
    uva 1599 ideal path(好题)——yhx
    uva 1572 self-assembly ——yhx
  • 原文地址:https://www.cnblogs.com/fengzhiyuan/p/7654375.html
Copyright © 2011-2022 走看看