tyvj1035棋盘覆盖——二分图匹配

题目:http://www.joyoi.cn/problem/tyvj-1035

把可放的位置作为节点,相邻的连边。

可用天然有的编号作为节点的编号。

果然只用连单向边就行了。也只需记录另一部的对应点。

注意易写错的那个地方。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n,m,x,y,head[10005],xnt,per[10005],ans;
bool vis[10005],in[10005],er[10005];
struct Node{
    int next,to;
}edge[20005];
void add(int x1,int y1,int x2,int y2)
{
    int u=n*(x1-1)+y1,v=n*(x2-1)+y2;
    edge[++xnt].next=head[u];
    edge[xnt].to=v;
    head[u]=xnt;
}
void ad(int x,int y)
{
    if(x>1&&!er[n*(x-2)+y])add(x,y,x-1,y);
    if(x<n&&!er[n*x+y])add(x,y,x+1,y);
    if(y>1&&!er[n*(x-1)+y-1])add(x,y,x,y-1);
    if(y<n&&!er[n*(x-1)+y+1])add(x,y,x,y+1);
}
bool dfs(int a)
{
    for(int i=head[a],v;i;i=edge[i].next)
        if(!vis[v=edge[i].to])
        {
            vis[v]=1;
            if(!per[v]||dfs(per[v]))//////dfs(per[v])  而不是dfs(v) 
            {
                per[v]=a;
                return true;
            }
        }
    return false;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        er[n*(x-1)+y]=1;
    }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            if((i+j)%2&&!er[n*(i-1)+j])
                ad(i,j);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            if((i+j)%2&&!in[n*(i-1)+j])
            {
                memset(vis,0,sizeof vis);
                int u=n*(i-1)+j;
                if(dfs(u))in[u]=1,ans++;
            }
    printf("%d",ans);
    return 0;
}

 

posted on 2018-03-06 22:40  Narh  阅读(150)  评论(0编辑  收藏  举报

导航