BZOJ 4808 浅谈精准卡时二分图最大独立集

BZOJ 4808 浅谈精准卡时二分图最大独立集_第1张图片
世界真的很大
这道题虽然并不是很难,但也算是卡了一下原先的不成熟二分图写法吧
按照自己的理解建的双向边用了这么久的却没有什么问题,但是在这道题上却完美的T掉了。。
无奈只得改成有二分图一侧向另一侧连单向边
不幸啊。。。付阔达

看题先:

description:

众所周知,马后炮是中国象棋中很厉害的一招必杀技。”马走日字”。本来,如果在要去的方向有别的棋子挡住(俗
称”蹩马腿”),则不允许走过去。为了简化问题,我们不考虑这一点。马跟马显然不能在一起打起来,于是rly在
一天再次借来了许多许多的马在棋盘上摆了起来……但这次,他实在没兴趣算方案数了,所以他只想知道在N×M的
矩形方格中摆马使其互不吃到的情况下的最多个数。但是,有一个很不幸的消息,rly由于玩得太Happy,质量本来
就不好的棋盘被rly弄坏了,不过幸好只是破了其中的一些格子(即不能再放子了),问题还是可以继续解决的。

input:

一行,两个正整数N和M。
接下来N行,每行M个数,要么为0,表示没坏,要么为1,表示坏了。
N<=200,M<=200

output:

一行,输出最多的个数。

最多能放多少马。。
两匹马不能共存于一张图上,只有他们各在“日字”的两端
那么就是对于“日”字的两端的点就是“有你没有他”的结构
再考虑到这是一张网格图
二分图的最大独立集。。
不能共存的两个点之间建一条边,最大匹配求最大独立集。

理论上是这样然后就跑匈牙利了
然后完美的T掉
上午写的这道题中午放这玩意儿在机房和网上标程对拍了一中午,没有问题
然后发现极限数据全是0我要跑7秒8秒
犹豫之后,还是改了写法
主要是200的范围4000的点1e6的边,实在是大了一点。。
尽量的缩减边数了

完整代码:

#include

struct edge
{
    int v,last;
}ed[4000010];

int n,m,num=0,tot=0,ans=0,cnt=0;
int head[100010],book[100010],match[100010],mp[330][330];
int fx[8]={2,2,1,-1,-2,-2,1,-1},fy[8]={1,-1,2,2,1,-1,-2,-2};

void add(int u,int v)
{
    num++;
    ed[num].v=v;
    ed[num].last=head[u];
    head[u]=num;
}

inline int dfs(int u)
{
    for(int i=head[u];i;i=ed[i].last)
    {
        int v=ed[i].v;
        if(book[v]!=tot)
        {
            book[v]=tot;
            if(!match[v] || dfs(match[v]))
            {
                match[v]=u,match[u]=v;
                return 1;
            }
        }
    }
    return 0;
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            scanf("%d",&mp[i][j]),cnt+=(!mp[i][j]);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        if((i+j)&1)
        {
            if(mp[i][j]) continue ;
            int S=(i-1)*m+j;
            for(int k=0;k<8;k++)
            {
                int x1=i+fx[k],y1=j+fy[k];
                if(x1>=1 && x1<=n && y1>=1 && y1<=m && !mp[x1][y1])
                    add(S,(x1-1)*m+y1);
            }
        }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        if((i+j)&1)
        {
            int S=(i-1)*m+j;
            if(mp[i][j]) continue ;
            tot++;
            if(!match[S]) ans+=dfs(S);
        }
    printf("%d\n",cnt-ans);
    return 0;
}
/*
EL PSY CONGROO
*/

嗯,就是这样

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