zoukankan      html  css  js  c++  java
  • 【复习】图论

    一、并查集

    1、普通并查集

    inline int father(int x)
    {
    	if(fath[x]==x) return x;
    	return fath[x]=father(fath[x]);
    }
    
    inline void Union(int x,int y)
    {
    	int f1=father(x),f2=father(y);
    	if(f1==f2) return;
    	fath[f1]=f2;
    }
    

    2、带权并查集

    如图,$dis[u]$表示$u$到$root-u$的距离,此时要合并两颗树,则以$root-v$为新根,$dis[ru]=Relationship(u,v)+dis[v]-dis[u]$。

    当路径压缩时,$dis[x]+=dis[fath[x]]$。

    此时有个重点,假如关系类型种类为$P$,所有$dis$要模$P$,关系种类满足递增性,循环性,可理解为$P$个一循环。

    重点例题: [HNOI2005]狡猾的商人 (多种关系), Rochambeau (三种关系) , True Liars (两种关系),食物链 (三种关系)

    inline int father(int x)
    {
    	if(fath[x]==x) return x;
    	int fa=father(fath[x]);
    	dis[x]=(dis[x]+dis[fath[x]])%P;
    	return fath[x]=fa;
    }
    
    inline void Union(int x,int y,int rela)
    {
    	int f1=father(x),f2=father(y);
    	if(f1==f2) return;
    	dis[f2]=(rela+dis[x]-dis[y]+P)%P;
    	fath[f2]=f1;
    }
    

    二、联通分量($O(n+m)$)

    1、强连通分量

    inline void Tarjan(int x)
    {
    	st.push(x);
    	vis[x]=1;
    	low[x]=dfn[x]=++idx;
    	for(int i=head[x];i;i=edge[i].nxt)
    	{
    		int v=edge[i].to;
    		if(!dfn[v])
    		{
    			Tarjan(v);
    			low[x]=min(low[v],low[x]);
    		}
    		else if(vis[v]) low[x]=min(low[x],dfn[v]);
    	}
    	if(low[x]==dfn[x])
    	{
    		int now=0;
    		ncon++;
    		while(now!=x)
    		{
    			now=st.top();
    			st.pop();
    			col[now]=ncon;
    			vis[now]=0;
    		}
    	}
    }
    

    2、边双联通分量(只加一个fa)

    inline void Tarjan(int x,int fa)
    {
    	st.push(x);
    	vis[x]=1;
    	low[x]=dfn[x]=++idx;
    	for(int i=head[x];i;i=edge[i].nxt)
    	{
    		int v=edge[i].to;
    		if(!dfn[v])
    		{
    			Tarjan(v,x);
    			low[x]=min(low[v],low[x]);
    		}
    		else if(vis[v] && v!=fa) low[x]=min(low[x],dfn[v]);
    	}
    	if(low[x]==dfn[x])
    	{
    		int now=0;
    		ncon++;
    		while(now!=x)
    		{
    			now=st.top();
    			st.pop();
    			col[now]=ncon;
    			new_val[ncon]+=val[now];
    			vis[now]=0;
    		}
    	}
    }
    

    3、点双联通分量

    不含桥,环与环必定含有公共边,且公共点至少两个,简单圈中的点一定属于同一个点BCC:

    inline void Tarjan(int x,int fa)
    {
    	st.push(x);
    	low[x]=dfn[x]=++idx;
    	vis[x]=1;
    	for(int i=head[x];i;i=edge[i].nxt)
    	{
    		int v=edge[i].to;
    		if(!dfn[v])
    		{
    			Tarjan(v,fa);
    			if(low[v]<low[x]) low[x]=low[v];
    			else if(low[v]>=low[x]) 
    			{
    				ncon++;
    				int now=0;
    				while(1)
    				{
    					now=st.top();
    					st.pop();
    			 		col[now]=ncon;
    					vis[now]=0;
    					if(now==v) break;
    				}
    				col[x]=ncon;
    			}
    		}
    		else if(vis[v]) low[x]=min(low[x],dfn[v]);
    	}
    }
    

      

    4、桥

    inline void Tarjan(int x,int fa)
    {
    	low[x]=dfn[x]=++idx;
    	for(int i=head[x];i;i=edge[i].nxt)
    	{
    		int v=edge[i].to;
    		if(!dfn[v])
    		{
    			Tarjan(v,x);
    			low[x]=min(low[x],low[v]);
    			if(low[v]>low[x]) bri.push(mp(x,v));
    		}
    		else if(v!=fa) low[x]=min(low[x],dfn[v]);
    	}
    }
    

    5、割点

    inline void Tarjan(int x,int fa)
    {
    	int child=0;
    	low[x]=dfn[x]=++idx;
    	for(int i=head[x];i;i=edge[i].nxt)
    	{
    		int v=edge[i].to;
    		if(!dfn[v])
    		{
    			Tarjan(v,x);
    			low[x]=min(low[x],low[v]);
    			if(low[v]>=dfn[x]) cut[x]=1;
    			child++;
    		}
    		else if(v!=fa) low[x]=min(low[x],dfn[v]);
    	}
    	if(child==1 && fa==0) cut[x]=0;
    }
    

    6、2-sat

    输出方案,对于每个对立的问题,选择BCC编号小的那个。

  • 相关阅读:
    异步运行
    ES6新增----深入理解generator
    ES6新增(箭头函数)
    ES6新增(有关变量)
    I2C写时序图[转]
    kernel中,dump_stack打印调用栈,print_hex_dump打印一片内存,记录一下
    http://man.linuxde.net/ 转
    Linux网络
    Linux基础:用tcpdump抓包(转)
    指针长度问题,不同架构的指针长度不同,可能32位,也可能64位,与unsigned long长度相同
  • 原文地址:https://www.cnblogs.com/linda-fcj/p/9298033.html
Copyright © 2011-2022 走看看