[Noi2016]网格

来自FallDream的博客,未经允许,请勿转载,谢谢。

 

跳蚤国王和蛐蛐国王在玩一个游戏。
他们在一个 n 行 m 列的网格上排兵布阵。其中的 c 个格子中 (0≤c≤nm),每个格子有一只蛐蛐,其余的格子中,每个格子有一只跳蚤。
我们称占据的格子有公共边的两只跳蚤是相邻的。
我们称两只跳蚤是连通的,当且仅当这两只跳蚤相邻,或存在另一只跳蚤与这两只跳蚤都连通。
现在,蛐蛐国王希望,将某些(0 个,1 个或多个)跳蚤替换成蛐蛐,使得在此之后存在至少两只跳蚤不连通。
例如:我们用图表示一只跳蚤,用图表示一只蛐蛐,那么图 1 描述了一个 n=4,m=4,c=2的情况。
这种情况下蛐蛐国王可以通过将第 2 行第 2 列,和第 3 行第 3 列的两只跳蚤替换为蛐蛐,从而达成他的希望,如图 2 所示。并且,不存在更优的方案,但是可能存在其他替换 2 只跳蚤的方案。
你需要首先判断蛐蛐国王的希望能否被达成。如果能够达成,你还需要最小化被替换的跳蚤的个数。

T<=20 1≤n,m≤10^9,0≤c≤min(nm,10^5) ∑c<=10^5

2s/1G

真是很蛋疼

当跳蚤数量小于2或者正好是一对还粘一起的时候答案是-1

当跳蚤本身不联通的时候答案是0

当存在一个点把图割开的时候是1

不然就是2

好像很简单 乱写了一通之后 成功获得了16分 真轻松  然后就去看了看题解

只保留在蛐蛐周围的5*5的格子内的跳蚤,四联通建图 建出的图等价 割点可以tarjan求出

然后如果有跳蚤不联通 那么会有一个蛐蛐的八联通块周围有两个不同的跳蚤联通块

感觉自己的码力不是很行啊  乱写一通 就这么丑了(吐血)

#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
#define ll long long
#define MN 100000
#define mod 2333333
using namespace std;
inline int read()
{
    int x = 0; char ch = getchar();
    while(ch < '0' || ch > '9') ch = getchar();
    while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
    return x;
}
int n,m,c,top,dn,ans,bel[MN*25+5],Cnt=0,Col=0,head[MN*25+5],en,tot,dfn[MN*25+5],low[MN*25+5],col[MN*2+5];
vector<int> v[MN+5],V[MN+5];
bool Cut[MN*25+5],b[MN+5];
struct P
{
    int x,y;
    P(int x=0,int y=0):x(x),y(y){}
    P operator+(P b){return P(x+b.x,y+b.y);}
}p[MN+5],Q[5],q[MN*25+5];
struct edge{int to,next;}e[MN*100+5];
struct My_Map
{
    int Head[mod+5],cnt;
    struct Hash{ll ha;int x,next;}s[25*MN+5];
    void clear()
    {
        cnt=0;
        memset(Head,0,sizeof(Head));
    }
    void ins(int X,int Y)
    {
        ll Ha=1LL*X*m+Y;int j=Ha%mod;
        s[++cnt]=(Hash){Ha,++Cnt,Head[j]};
        Head[j]=cnt;
    }
    int Check(int X,int Y)
    {
        ll Ha=1LL*X*m+Y;int j=Ha%mod;
        for(int i=Head[j];i;i=s[i].next)
            if(s[i].ha==Ha) return s[i].x;
        return 0;
    }
}mp;
inline void ins(int f,int t){e[++en]=(edge){t,head[f]};head[f]=en;}
inline int abs(int x){return x<0?-x:x;}
bool Check()
{
    if(1LL*n*m-c>2) return false;
    if(1LL*n*m-c<=1) return true;
    top=0;
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m&&top<2;++j)
            if(!mp.Check(i,j)) Q[++top]=P(i,j);
    if(Q[1].x==Q[2].x&&abs(Q[1].y-Q[2].y)==1) return true;
    if(Q[1].y==Q[2].y&&abs(Q[1].x-Q[2].x)==1) return true;
    return false;
}
const int dis[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
void build()
{
    for(int i=1;i<=c;++i)
        for(int j=-2;j<=2;++j)
            for(int k=-2;k<=2;++k)
                if(j||k)
                {
                    int x=p[i].x+j,y=p[i].y+k;
                    if(x<=0||y<=0||x>n||y>m||mp.Check(x,y)) continue;
                    mp.ins(x,y);q[Cnt]=P(x,y);
                }
    for(int i=1,k;i<=Cnt;++i)
        for(int j=0;j<4;++j)
        {
            int x=q[i].x+dis[j][0],y=q[i].y+dis[j][1];
            if(x<=0||y<=0||x>n||y>m||(k=mp.Check(x,y))<=0) continue;
            ins(i,k);
        }
}

void tj(int x,int fa)
{
    dfn[x]=low[x]=++dn;bel[x]=tot;Cut[x]=0;int son=0;
    for(int i=head[x];i;i=e[i].next)if(e[i].to!=fa)
    {
        if(!dfn[e[i].to])
        {
            ++son,tj(e[i].to,x),low[x]=min(low[x],low[e[i].to]);
            if(low[e[i].to]>=dfn[x]) Cut[x]=1;
        }
        else low[x]=min(low[x],dfn[e[i].to]);
    }
    if(son==1&&!fa) Cut[x]=0;
}

bool Round(int id)
{
    for(int i=-1;i<=1;++i)
        for(int j=-1;j<=1;++j)
            if(i||j)
            {
                int x=q[id].x+i,y=q[id].y+j;
                if(x&&y&&mp.Check(x,y)<0)return 1;
            }
    return 0;
}

bool check(int t)
{
    int col=-1;
    for(int l=0;l<V[t].size();++l)
    {
        int X=p[V[t][l]].x,Y=p[V[t][l]].y;
        for(int i=-2;i<=2;++i)
            for(int j=-2,k;j<=2;++j)
                if(i||j)
                {
                    int x=X+i,y=Y+j;
                    if(x<1||y<1||x>n||y>m||(k=mp.Check(x,y))<0) continue;
                    if(col==-1) col=bel[k];
                    else if(col!=bel[k]) return true;
                }
    }
    return false;
}

void Dfs(int x)
{
    col[x]=Col;V[Col].push_back(x);
    for(int j=0;j<v[x].size();++j)
        if(!col[v[x][j]]) Dfs(v[x][j]);
}

int main()
{
    for(int T=read();T;--T)
    {
        n=read();m=read();c=read();ans=2;mp.clear();
        if(m==1||n==1) ans=1;Cnt=-c-1;
        for(int i=1;i<=c;++i)
            p[i].x=read(),p[i].y=read(),mp.ins(p[i].x,p[i].y);
        if(Check()) puts("-1");
        else
        {
            Cnt=0;en=0;tot=0;dn=0;Col=0;build();
            for(int i=1,k;i<=c;++i)
                for(int j=0;j<4;++j)
                {
                    int x=p[i].x+dis[j][0],y=p[i].y+dis[j][1];
                    if(x<1||y<1||x>n||y>m) continue;
                    if((k=mp.Check(x,y))<0) v[i].push_back(k+c+1);
                }
            for(int i=1;i<=c;++i)
                if(!col[i]) ++Col,Dfs(i);
            for(int i=1;i<=Cnt;++i)
                if(!dfn[i]) ++tot,tj(i,0);
            for(int i=1;i<=Cnt&&ans>1;++i) if(Cut[i]&&Round(i)) ans=1;
            for(int i=1;i<=Col&&ans;++i)
                if(check(i)) ans=0;
            printf("%d
",ans);
            memset(head,0,sizeof(int)*(Cnt+5));
            for(int i=1;i<=c;++i) v[i].clear(),V[i].clear();
            memset(dfn,0,sizeof(int)*(Cnt+5));
            memset(low,0,sizeof(int)*(Cnt+5));
            memset(col,0,sizeof(int)*(c+5));
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/FallDream/p/Noi2016d1t2.html