BZOJ 3175 攻击装置

Posted on 2017-01-22 17:54  ziliuziliu  阅读(162)  评论(0编辑  收藏  举报

本质上是二分图求最大独立集。

优化:不必建两列点,只用建一列就好了。因为hungary本质上是使用ly[]这个数组,和是不是两列点没有关系。如果建了两列点仿佛过不了这道题。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 205
#define maxv 80050
#define maxe 500500 
using namespace std;
int n,map[maxn][maxn],g[maxv],nume=1,ans=0,ly[maxv],flag=0,used[maxv],tot=0;
int dx[]={0,-2,-1,1,2,2,1,-1,-2},dy[]={0,1,2,2,1,-1,-2,-2,-1};
struct edge
{
    int v,nxt;
}e[maxe];
char s[maxn];
void addedge(int u,int v)
{
    e[++nume].v=v;
    e[nume].nxt=g[u];
    g[u]=nume;
}
int f(int x,int y) {return (x-1)*n+y;}
bool judge(int x,int y)
{
    return ((x>=1) && (x<=n) && (y>=1) && (y<=n));
}
bool hungary(int x)
{
    for (int i=g[x];i;i=e[i].nxt)
    {
        int v=e[i].v;
        if (used[v]==flag) continue;
        used[v]=flag;
        if ((ly[v]==-1) || (hungary(ly[v])))
        {
            ly[v]=x;
            return true;
        }
    }
    return false;
}
int main()
{
    scanf("%d",&n);
    memset(ly,-1,sizeof(ly));
    for (int i=1;i<=n;i++)
    {
        scanf("%s",s);
        for (int j=0;j<n;j++)
        {
            map[i][j+1]=s[j]-'0';
            if (!map[i][j+1]) tot++;
        }
    }
    for (int i=1;i<=n;i++)
        for (int j=1;j<=n;j++)
            for (int k=1;k<=4;k++)
            {
                int nx=i+dx[k],ny=j+dy[k];
                if (judge(nx,ny) && (!map[nx][ny]) && (!map[i][j]))
                {
                    addedge(f(i,j),f(nx,ny));
                    addedge(f(nx,ny),f(i,j));
                }
            }
    for (int i=1;i<=n*n;i++)
    {
        if (!g[i]) continue;
        flag++;
        if (hungary(i)) ans++;
    }
    printf("%d\n",tot-ans/2);
    return 0;
}