染色法判断二分图

写的很菜 , 欢迎建议、补充

二分图的定义

图G=(V,E),顶点集V可分割为两个互不相交的子集,并且图中每条边依附的两个顶点都分属于这两个互不相交的子集,两个子集内的顶点不相邻。-----百科

就是当一个东西可以分成两半的时候,你可以问自己一下这满足不满足二分图的性质。

解释的很草率 ↑    ,   题解里向来都是说 : "显而易见这是二分图", 我也不好这么说 , 题做得还少, 这几天多练练没准就找到手感了 。

当你定好了解题的方向,那么如何判定这个是二分图呢 。

染色法 。

需要两种颜色,我们从任意点开始染色, 把与其相邻的点染成与它相反的颜色 , 整个图染完色之后,如果满足相连的两个点颜色都不同, 那么就可以断定它是二分图了 , 如果发现相连点颜色相同 ,那就满足不了二分图的定义了。  

这个染色过程通过BFS或者DFS实现。

下面贴个BFS代码  , DFS同理。

 1 void connect(int x,int y)//拿邻接表存的图,用vector也可以。 
 2 {
 3     pre[++cnt]=last[x];
 4     other[cnt]=y;
 5     last[x]=cnt;
 6 } 
 7 void BFS(int x)
 8 {
 9     queue <int>q;
10     q.push(x);
11     color[x]=1;            //BFS染色 
12     while(!q.empty())
13     {
14         int tmp=q.front();
15         q.pop();
16         for(int i=last[tmp];i;i=pre[i])
17         {
18             int to=other[i];
19             if(to==tmp)continue;
20             if(color[to]==color[tmp]){        //发现相邻点的颜色相等,于是这个图不是二分图 
21                 exit(0);
22             }
23             else{
24                 color[to]=1^color[tmp];        //把相邻点涂成相反的颜色,然后把这个点加入队列 
25                 q.push(to);
26             }
27         }
28     }
29 }
30 int main()
31 {
32     memset(color,-1,sizeof(color));
33     for(int i=1;i<=N;i++)
34         if(color[i]==-1)BFS(i);                //=、= 
35 }

判断二分图的代码就这样↑

 

下面给道可爱的例题

NOIP2008  双栈排序 (可以在LuoguP1155提交)

戳链接https://www.luogu.org/problem/show?pid=1155看题面,就不粘贴了

这个题就是有一个序列,给你两个栈,通过进栈退栈输出一个排序的序列 

(按理来说肯定不能纯模拟做,虽然题解里有一个超级长的纯模拟代码)

联想到二分图,我们应该去思考如何把这些数分成两部分,分别放进两个栈里

下面我们要考虑怎样的两个元素可以放到一个栈里面,

显然的 ,当i<j<k , a[k]<a[i]<a[j],i和j是不能放到同一个栈里的 ,于是i,j就可以构成图的两个子集的一条边 

我们枚举出来所有的i,j 进行连边,

    for(int i=N-1;i>=1;i--)sufmin[i]=min(sufmin[i+1],a[i+1]);
    for(int i=1;i<=N;i++)
        for(int j=i+1;j<=N;j++)
            if(a[i]<a[j]&&a[i]>sufmin[j]){
            connect(i,j);connect(j,i);
        }

之后利用上面的染色法判定二分图,就可以把所有的数分成两部分,再进行简单的模拟,就可以得到答案了。

如果不是这个不是二分图,那就说明无解。

 

先写这么多了,很啰嗦求见谅,学了新的再加内容。

 

原文地址:https://www.cnblogs.com/Elfish/p/7535169.html