bzoj2150: 部落战争

补了一下匈牙利的各种骚操作。

最大匹配等于最小覆盖

最大独立集=n-最小覆盖

最大团=补图的最大独立集

 

对于这题,把每个点拆成两个,可以到达的就连边。

我匈牙利的模版是真不熟。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
int dx[4]={1,1,1,1};
int dy[4]={1,-1,1,-1};

struct node
{
    int x,y,next;
}a[210000];int len,last[3100];
void ins(int x,int y)
{
    len++;
    a[len].x=x;a[len].y=y;
    a[len].next=last[x];last[x]=len;
}

int match[3100];
bool chw[3100];
bool find_muniu(int x)
{
    for(int k=last[x];k;k=a[k].next)
    {
        int y=a[k].y;
        if(chw[y]==true)
        {
            chw[y]=false;
            if(match[y]==0||find_muniu(match[y])==true)
            {
                match[y]=x;
                return true;
            }
        }
    }
    return false;
}

int nm,num[110][110];
char ss[110][110];
int main()
{
    int n,m,R,C;
    scanf("%d%d%d%d",&n,&m,&R,&C);
    for(int i=0;i<=1;i++)
    {
        dx[i]*=R,dy[i]*=C;
        dx[i+2]*=C,dy[i+2]*=R;
    }
    nm=0;
    for(int i=1;i<=n;i++)
    {
        scanf("%s",ss[i]+1);
        for(int j=1;j<=m;j++)
            if(ss[i][j]=='.')num[i][j]=++nm;
    }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(ss[i][j]=='.')
                for(int t=0;t<=3;t++)
                {
                    int ti=i+dx[t],tj=j+dy[t];
                    if(ti>0&&ti<=n&&tj>0&&tj<=m&&ss[ti][tj]=='.')
                        ins(num[i][j],num[ti][tj]);
                }
            
    int ans=0;
    memset(match,0,sizeof(match));
    for(int i=1;i<=nm;i++)
    {
        memset(chw,true,sizeof(chw));
        if(find_muniu(i)==true)ans++;
    }
    printf("%d\n",nm-ans);
    return 0;
}

 

posted @ 2018-03-23 08:23  AKCqhzdy  阅读(149)  评论(0编辑  收藏  举报