牛客OI周赛1-提高组 A-分组

玄学之门

  • 题目:
  • 分析:
  • 代码:
  • 玄中之玄:


题目:

传送门


分析:

看到题目 b b bb bb一堆,这里我们转换下:

在有n个节点的图中,每个节点的度数不超过3,现在要我们对其进行黑白染色,使得相邻节点中只出现至多2个相同颜色的节点

现在我们很容易想到用二分图做,但本蒟蒻不会呀,可仍然有更优更简单的方法:用 d f s dfs dfs来进行黑白染色
怎么讲呢,我们通过 d f s dfs dfs不断更正我们的答案
首先对于当前节点 ( n o w ) (now) (now)的字节点 ( u ) (u) (u),当 u u u没有答案时,我们将以 n o w now now的答案取反填入,再以 u u u进行 d f s dfs dfs
可显然,会在这个过程中出现多个相同颜色的节点,那么我们可以考虑在 d f s dfs dfs求出子节点的答案后统计与 n o w now now相同颜色的节点数,遍历完所有子节点后,当统计的数 > 1 >1 >1(即有多个相同颜色的节点),我们就可以直接将 n o w now now的答案取反
至此,本题就基本结束了


代码:

#include
#include
#include
#include 
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define LL long long
#define ch cheap
#define XJQ (int)1000000007
using namespace std;
inline LL read() {
    LL d=0,f=1;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9'){d=d*10+s-'0';s=getchar();}
    return d*f;
}
struct node{
    int t,n;
}t[300005];
int ls[300005],cnt=0;
int ans[(int)1e5+5];
void dfs(int now)
{
    int sum=0;
    for(int i=ls[now];~i;i=t[i].n)
    {
        int u=t[i].t;
        if(!ans[u]) ans[u]=ans[now]^3,dfs(u);
        if(ans[now]==ans[u]) sum++;
    }
    if(sum>1) ans[now]^=3;
    return;
}
int main()
{
    int n=read(),m=read();
    memset(ls,-1,sizeof(ls));
    for(int i=1;i<=m;i++)
    {
        int x=read(),y=read();
        t[cnt]=(node){y,ls[x]};ls[x]=cnt++;
        t[cnt]=(node){x,ls[y]};ls[y]=cnt++;
    }
    for(int i=1;i<=n;i++)
    {
        if(!ans[i]) ans[i]=1,dfs(i);
        printf("%d ",ans[i]);
    }
    return 0;
}

玄中之玄:

用该种算法,是不能做到 A C AC AC题目样例的,但因为有 S p e c i a l Special Special J u d i n g Juding Juding,所以还是可以 A A A

你可能感兴趣的:(黑白染色)