• 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 }
  • 相关阅读:
    POJ 3468_A Simple Problem with Integers(树状数组)
    POJ 3468_A Simple Problem with Integers(线段树)
    ZOJ 2770_Burn the Linked Camp
    ZOJ 2770_Burn the Linked Camp
    POJ 3169_Layout
    POJ 3169_Layout
    POJ 3684_Physics Experiment
    POJ 3255_Roadblocks
    POJ 3723 Conscription【最小生成树】
    POJ 3279 Fliptile【枚举】
  • 原文地址:https://www.cnblogs.com/fengzhiyuan/p/7654375.html
Copyright © 2020-2023  润新知