二分图最大独立集--luoguP3355 骑士共存问题

传送门

可以把互相攻击的两个点之间连一条边,是一个二分图,每个边只能取一个点

所以就是最大独立集

然后最大独立集就等于n-最大匹配

但是这玩意复杂度不太对劲啊

一直T90分后来换了一下加边顺序就过了???(就是那个dx和dy数组

#include
#include
#include
#include
#include
#define N 40005 
#define id(x,y) ((x-1)*n+y)
using namespace std;
int n,m,cnt,head[N],lk[N],ans,tot,vis[N];
//int dx[]={1,2,2,1,-1,-2,-2,-1};
//int dy[]={2,1,-1,-2,2,1,-1,-2};
int dx[]={2,1,-1,-2,-2,-1,1,2};
int dy[]={1,2,2,1,-1,-2,-2,-1};

bool ban[205][205];

inline int rd(){
    int x=0,f=1;char c=' ';
    while(c<'0' || c>'9') f=c=='-'?-1:1,c=getchar();
    while(c<='9' && c>='0') x=x*10+c-'0',c=getchar();
    return x*f;
}

struct EDGE{
    int to,nxt;
}edge[N<<4];

inline void add(int x,int y){
    edge[++cnt].to=y; edge[cnt].nxt=head[x]; head[x]=cnt;
}

inline bool judge(int x,int y){
    return x>=1&&x<=n&&y>=1&&y<=n&&(!ban[x][y]);
}

inline void build(){
    for(register int i=1;i<=n;i++)
        for(register int j=1+(i&1);j<=n;j+=2)
            if(!ban[i][j])
            for(register int k=0;k<8;k++){
                int x=i+dx[k],y=j+dy[k];
                if(judge(x,y))
                    add(id(i,j),id(x,y));
            }
}

bool dfs(int u){
    for(register int i=head[u];i;i=edge[i].nxt){
        int v=edge[i].to;
        if(vis[v]==tot) continue; vis[v]=tot;
        if(!lk[v] || dfs(lk[v])){
            lk[v]=u; return true;
        }
    } return false;
}

int main(){
    n=rd(); m=rd();
    for(register int i=1;i<=m;i++){
        int x=rd(),y=rd();
        ban[x][y]=1;
    }
    build();
    for(register int i=1;i<=n;i++)
        for(register int j=1+(i&1);j<=n;j+=2)
            if(!ban[i][j]){
                tot++;
                if(dfs(id(i,j))) ans++;
            }
    printf("%d\n",n*n-m-ans);
    return 0;
}

 

你可能感兴趣的:(二分图)