UVALive 6525 Attacking rooks

将行中连续的' . '当作X集的一个点,列中连续的’ . ‘看成Y集中的一个点,然后把每一个’ . ‘看成一条边,连接Xi,Yj。

则问题转化成求此二分的最大匹配数。每找到一条匹配边的意义是找到了一个点放置一个,并且覆盖了所在的连续的行和列。

所以答案即为此二分图的最大匹配。

20s的时限,只跑了29ms。。。。这是有多不相信自己的服务器。。。。

#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <queue>
#include <cmath>
#include <stack>
#include <map>

#pragma comment(linker, "/STACK:1024000000");
#define EPS (1e-8)
#define LL long long
#define ULL unsigned long long LL
#define _LL __int64
#define _INF 0x3f3f3f3f
#define Mod 1000000007
#define LM(a,b) (((ULL)(a))<<(b))
#define RM(a,b) (((ULL)(a))>>(b))

using namespace std;

const LL MAXN = 100001;

struct N
{
    int v,next;
}edge[MAXN*2];

int head[MAXN];

int Top;

void Link(int u,int v)
{
    edge[Top].v = v;

    edge[Top].next = head[u];
    head[u] = Top++;
}

void Init_head_Top(int n)
{
    memset(head,-1,sizeof(int)*(n+2));
    Top = 0;
}

int Match_Point[MAXN];

bool mark[MAXN];

bool dfs(int s)
{
    for(int p = head[s] ; p != -1; p = edge[p].next)
    {
        if(mark[edge[p].v] == false)
        {
            mark[edge[p].v] = true;
            if(Match_Point[edge[p].v] == -1 || dfs(Match_Point[edge[p].v]))
            {
                Match_Point[s] = edge[p].v;
                Match_Point[edge[p].v] = s;
                return true;
            }
        }
    }
    return false;
}

int Cal_Max_Match(int n)
{
    int ans = 0;

    for(int i = 1;i <= n; ++i)
    {
        if(Match_Point[i] == -1)
        {
            memset(mark,false,sizeof(bool)*(n+2));
            if(dfs(i))
                ans++;
        }
    }
    return ans;
}

char Map[110][110];

int ansx[110][110];
int ansy[110][110];

int main()
{
    int n;

    int i,j;

    while(scanf("%d",&n) != EOF)
    {
        for(i = 1;i <= n; ++i)
        {
            scanf("%s",Map[i]+1);
        }

        memset(ansx,-1,sizeof(ansx));
        memset(ansy,-1,sizeof(ansy));
        memset(Match_Point,-1,sizeof(int)*(n*n*2+2));

        int ty = 0;

        for(i = 1;i <= n; ++i)
        {
            for(j = 1;j <= n; ++j)
            {
                if(Map[i][j] == '.')
                {
                    ansx[i][j] = (ansx[i][j-1] == -1 ? ++ty : ansx[i][j-1]);
                }
            }
        }

        Init_head_Top(n*n*2);

        int ans = 0;

        for(j = 1;j <= n; ++j)
        {
            for(i = 1;i <= n; ++i)
            {
                if(Map[i][j] == '.')
                {
                    ansy[i][j] = (ansy[i-1][j] == -1 ? ++ty : ansy[i-1][j]);
                    Link(ansx[i][j],ansy[i][j]);
                    Link(ansy[i][j],ansx[i][j]);
                    if(Match_Point[ansx[i][j]] == -1 && Match_Point[ansy[i][j]] == -1)
                    {
                        Match_Point[ansx[i][j]] = ansy[i][j],Match_Point[ansy[i][j]] = ansx[i][j],ans++;
                    }
                }
            }
        }

        printf("%d\n",ans+Cal_Max_Match(ty));

    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值