bzoj 3175 攻击装置 | 二分图最大独立集

显然日字是从黑点到白点,所以黑白染色做独立集就行了。
注意连边的时候要让它先和位于它下面的点匹配,因为下面的点未匹配的概率更大,dfs的深度也更小。 我开始先匹配的上面的点,t了。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>

#define md
#define ll long long
#define inf (int) 1e9
#define eps 1e-8
#define N 210
#define M 40010
using namespace std;
struct yts { int x,t,ne; } e[8*M];
int g[N][N];
char st[N][N];
int v[M],vis[M],link[M];
int lx[8]={-1,-1,-2,-2,1,1,2,2,},ly[8]={2,-2,1,-1,2,-2,1,-1};
int num=0;
void put(int x,int y)
{
num++; e[num].x=x; e[num].t=y;
e[num].ne=v[x]; v[x]=num;
}
bool dfs(int x,int tm)
{
if (vis[x]==tm) return 0;
vis[x]=tm;
for (int i=v[x];i;i=e[i].ne)
{
int y=e[i].t;
if (!link[y]||dfs(link[y],tm))
{
link[y]=x;
return 1;
}
}
return 0;
}
void outit()
{
for (int i=1;i<=num;i++) printf("%d %d\n",e[i].x,e[i].t);
}
int main()
{
int n,ans=0;
scanf("%d",&n);
int tot=0;
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
g[i][j]=++tot;
for (int i=1;i<=n;i++) scanf("%s",st[i]+1);
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
{
if (st[i][j]=='1') continue;
ans++;
if ((i&1)^(j&1)) continue;
for (int k=0;k<=7;k++)
{
int x=i+lx[k],y=j+ly[k];
if (x<1||y<1||x>n||y>n||st[x][y]=='1') continue;
put(g[i][j],g[x][y]);
}
}
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
{
if (st[i][j]=='1') continue;
if ((i&1)^(j&1)) continue;
if (!link[g[i][j]]) ans-=dfs(g[i][j],g[i][j]);
}
//outit();
printf("%d\n",ans);
return 0;
}

你可能感兴趣的:(bzoj 3175 攻击装置 | 二分图最大独立集)