zoukankan      html  css  js  c++  java
  • 图论模版

    图论模版

     

    目录

    图论模版

     

    1.强联通

    2.割点

    hdu3671 Boonie and Clyde

    3.割边

    4.点双

    5.边双

    POJ 2723 Get Luffy Out


    1.强联通

    判断图是否强联通

    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #define maxn 10002
    using namespace std;
    int n,m,head[maxn],t1,t2,tot;
    int low[maxn],dfn[maxn],zh[maxn],top,sc,ins[maxn],cnt;
    struct node{
    	int v,nex;
    }e[100002];
    int ss(){
    	int v=0;char ch;
    	while(!isdigit(ch=getchar()));v=v+ch-48;
    	while(isdigit(ch=getchar()))v=v*10+ch-48;
    	return v;
    }
    void lj(int t1,int t2){
    	e[++tot].v=t2;e[tot].nex=head[t1];head[t1]=tot;
    }
    void tarjan(int k){
    	dfn[k]=low[k]=++sc;
    	zh[++top]=k;ins[k]=1;
    	for(int i=head[k];i;i=e[i].nex){
    		if(!dfn[e[i].v]){
    			tarjan(e[i].v);
    			low[k]=min(low[k],low[e[i].v]);
    		}
    		else if(ins[e[i].v])low[k]=min(low[k],dfn[e[i].v]);
    	}
    	if(dfn[k]==low[k]){
    		cnt++;if(cnt>1)return;
    		while(top>0){
    			ins[zh[top]]=0;
    			if(zh[top]==k){top--;break;}
    			top--;
    		}
    	}
    }
    void Q(){
    	for(int i=1;i<=10000;i++)head[i]=low[i]=dfn[i]=0;
    	sc=0,tot=0;cnt=0;top=0;
    }
    int main(){
    	while(~scanf("%d%d",&n,&m)&&n){
    		Q();
    		for(int i=1;i<=m;i++){
    			t1=ss();t2=ss();
    			lj(t1,t2);
    		}
    		for(int i=1;i<=n;i++){
    			if(!dfn[i])tarjan(i);
    		}
    		if(cnt>1)puts("No");
    		else puts("Yes");
    	}
    	return 0;
    }

    2.割点

    hdu3671 Boonie and Clyde

    给一个无向图,要求毁掉两个点,使图变得不连通,图一开始是连通的
     

    做法:先枚举要删除的第1个点,在原图中删除它,看看删除它后整个图的变化

            1.整个图变得不连通了(即这个点本身是割点),但是还没完要分类讨论一下

            (1).整个图变为两部分,但是两部分刚好都是一个点,那么这两个点再毁掉哪个点都好,图的连通分支数都不会增加,这是一个特殊情况

          例如,(1,2)(2,3)这种图,是无解的,任意毁掉两个点都无法增加图的连通分支,所以方案数为0

            (2).整个图分为两部分,但是有一部分的点数为1,另一部分大于1,那么这时候只要在较大的那部分,任意毁掉一个点(无论是不是割点都行),最后整个图都会至少被分为了两个部分

                    (如果毁掉的是割点,将分成更多份),所以这样产生的方案数是V-2

            (3).整个图分为了两个部分,两个部分的点数都大于1,那么任意在哪个部分毁掉那个点都可以(无论是不是割点都行),最后整个图都会至少分为两个部分,所以方案数为V-1

            (4).整个图被分为了三个或更多的部分,那么也是在剩下的点中任意毁掉一个点都可以(无论那个点是不是割点),方案数为V-1

                  (如果这个点刚好处于一个部分且这个部分只有它自己一个点,那么    毁掉后整个图的分支数减1;如果这个点在一个部分且这个部分不止它一个点且这个点不是割点,那么分支数  不会增加,如果是割点分支数为增加)

         2.删除第一个点后,整个图还是连通的(是连通,不是双连通)

            那么就在剩下的图中找割点,找到几个,方案数就是多少

    来自https://www.cnblogs.com/scau20110726/archive/2013/05/22/3092078.html

    割点条件:

    1.k是树根且有两棵以上子树

    2.low[e[i].v]>=dfn[k] 

    记的判断e[i].v!=fa

    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #define maxn 1005
    using namespace std;
    int n,m,head[maxn],tot,t1,t2,now;
    int dfn[maxn],low[maxn],flag[maxn],sum,sc,T;
    struct node
    {
    	int v,nex;
    }e[20002];
    void lj(int t1,int t2){
    	tot++;e[tot].v=t2;e[tot].nex=head[t1];head[t1]=tot;
    }
    void Q1(){
    	tot=0;
    	memset(head,0,sizeof head);
    }
    void Q2(){
    	for(int i=1;i<=n;i++)low[i]=dfn[i]=flag[i]=0;
    	sum=0;sc=0;
    }
    int tarjan(int k,int fa)
    {
    	dfn[k]=low[k]=++sc;
    	int kid=0,ss=0;
    	for(int i=head[k];i;i=e[i].nex){
    		if(e[i].v==now)continue;
    		if(!dfn[e[i].v]){
    			ss+=tarjan(e[i].v,k);kid++;
    			low[k]=min(low[k],low[e[i].v]);
    			if(fa==0&&kid==2)flag[k]=1;
    			if(fa!=0&&low[e[i].v]>=dfn[k])flag[k]=1;
    		}
    		else if(e[i].v!=fa){
    			low[k]=min(low[k],dfn[e[i].v]);
    		}
    	}
    	sum+=flag[k];
    	return ss+1;
    }
    int main()
    {
    	while(~scanf("%d%d",&n,&m)&&n){
    		Q1();
    		for(int i=1;i<=m;i++){
    			scanf("%d%d",&t1,&t2);
    			lj(t1,t2);lj(t2,t1);
    		}
    		int ans=0;
    		for(now=1;now<=n;now++){
    			Q2();int co=0,ff=0;
    			for(int i=1;i<=n;i++){
    				if(!dfn[i]&&i!=now){
    					int fsy=tarjan(i,0);
    					co++;
    					if(fsy==1)ff++;
    				}
    			}
    			if(co>2)ans=ans+n-1;
    			else if(co==2){
    				if(ff==2)ans-=2;
    				if(ff==1)ans--;
    				ans=ans+n-1;
    			}
    			else ans=ans+sum;
    			//cout<<ans<<' '<<co<<' '<<ff<<endl;
    		}
    		printf("Case %d: %d
    ",++T,ans/2);
    	}
    	return 0;
    }

    3.割边

    hdu4738 Caocao's Bridges 

    题意 :求最小桥,注意,这题如果不连通输出0

    连通的话,如果,最小桥是0刚要输出1,因为,必须派一个人

    注意重边!!!!

    if(fa==(i^1))continue; 

    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #define maxn 1002
    using namespace std;
    int n,m,head[maxn],t1,t2,t3,tot=1;
    int dfn[maxn],low[maxn],sc,Min,co;
    struct node{
    	int v,w,nex;
    }e[4000006];
    void lj(int t1,int t2,int t3)
    {
    	e[++tot].v=t2;e[tot].w=t3;e[tot].nex=head[t1];head[t1]=tot;
    }
    void tarjan(int k,int fa)
    {
    	//co++;
    	dfn[k]=low[k]=++sc;
    	for(int i=head[k];i;i=e[i].nex){
    	//	if(e[i].v==fa)continue;  FUCK CHONGBIAN 
    	if(fa==(i^1))continue; 
    		if(!dfn[e[i].v]){
    			tarjan(e[i].v,i);
    			low[k]=min(low[k],low[e[i].v]);
    			if(low[e[i].v]>dfn[k])Min=min(Min,e[i].w);	
    		}
    		else low[k]=min(low[k],dfn[e[i].v]);
    	}
    }
    void Q(){
    	for(int i=1;i<=1000;i++)dfn[i]=low[i]=0,head[i]=0;
    	tot=1,sc=0;co=0;
    }
    int main(){
    	while(~scanf("%d%d",&n,&m) &&n){
    		Q();
    		for(int i=1;i<=m;i++){
    			scanf("%d%d%d",&t1,&t2,&t3);
    			lj(t1,t2,t3);lj(t2,t1,t3);
    		}
    		Min=1e9;co=0;
    		for(int i=1;i<=n;i++){
    			if(!dfn[i])tarjan(i,0),co++;
    		}
    		if(co>1)puts("0");
    		else if(Min==1e9)puts("-1");
    		else if(Min==0)puts("1");
    		else cout<<Min<<endl;
    	}
    	return 0;
    }

    4.点双

    例题

    https://blog.csdn.net/liankewei123456/article/details/81623907

    记的是保存边

    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #define maxn 1002
    #define M 2000006 
    using namespace std;
    int n,m,t1,t2,head[maxn],fl[maxn][maxn],tot;
    int dfn[maxn],low[maxn],zh[M],top,sc,cnt,he[maxn],tt;
    int flag[maxn],co[maxn],fsy[maxn];
    struct node{
    	int nex,u,v;
    }e[M],h[M];
    void lj(int t1,int t2){
    	e[++tot].v=t2;e[tot].u=t1;e[tot].nex=head[t1];head[t1]=tot;
    }
    void add(int t1,int t2){
    	h[++tt].v=t2,h[tt].nex=he[t1];he[t1]=tt;
    }
    void lian(int u,int v){
    	cnt++;
    	while(top>0){
    		t1=e[zh[top]].u,t2=e[zh[top]].v;
    		add(cnt,t1);add(cnt,t2);
    		if(t1==u&&t2==v){top--;break;}
    		top--;
    	}
    }
    void tarjan(int k,int fa){
    	dfn[k]=low[k]=++sc;
    //	cout<<k<<' '<<dfn[k]<<endl;
    	for(int i=head[k];i;i=e[i].nex){
    		//cout<<"fsy "<<e[i].v<<endl;
    		if(e[i].v==fa)continue;
    		if(!dfn[e[i].v]){
    			zh[++top]=i;
    			tarjan(e[i].v,k);
    			low[k]=min(low[k],low[e[i].v]);
    			if(low[e[i].v]>=dfn[k])lian(k,e[i].v);//geding
    		}
    		else{
    			if(low[k]>dfn[e[i].v]){
    				low[k]=dfn[e[i].v];
    				zh[++top]=i;
    			}
    		}
    	}
    //	cout<<"aa "<<k<<' '<<low[k]<<endl;
    }
    bool pd(int k){
    	for(int i=head[k];i;i=e[i].nex){
    		if(!flag[e[i].v])continue;
    		if(!co[e[i].v]){
    			co[e[i].v]=3-co[k];
    			if(!pd(e[i].v))return 0;
    		}
    		else if(co[e[i].v]!=3-co[k])return 0;
    	}
    	return 1;
    }
    void Q()
    {
    	sc=tot=tt=0;
    	for(int i=1;i<=1000;i++)
    	head[i]=he[i]=dfn[i]=low[i]=fsy[i]=0;
    	memset(fl,0,sizeof fl);
    	memset(e,0,sizeof e);memset(h,0,sizeof h);
    }
    int main(){
    	while(~scanf("%d%d",&n,&m)&&n){
    		Q();
    		for(int i=1;i<=m;i++){
    			scanf("%d%d",&t1,&t2);
    			fl[t1][t2]=fl[t2][t1]=1;
    		}
    		for(int i=1;i<=n;i++)
    		for(int j=1;j<=n;j++){
    			if(!fl[i][j]&&i!=j)lj(i,j);
    		}
    		for(int i=1;i<=n;i++){
    			if(!dfn[i])tarjan(i,0);
    		}
    		for(int x=1;x<=cnt;x++){
    			memset(flag,0,sizeof flag);
    			memset(co,0,sizeof co);
    			for(int i=he[x];i;i=h[i].nex)flag[h[i].v]=1;
    			//cout<<x<<endl;
    			//for(int i=he[x];i;i=h[i].nex)cout<<h[i].v<<' ';cout<<endl;
    			int S=h[he[x]].v;co[S]=1;
    			if(!pd(S)){
    				for(int i=he[x];i;i=h[i].nex)fsy[h[i].v]=1;
    			}//youjihuan  keyicanjia
    		}
    		int ans=n;
    		for(int i=1;i<=n;i++)ans-=fsy[i];
    		cout<<ans<<endl;
    	}
    	return 0;
    }

    5.边双

    poj 3352 Road Construction

       给定一个连通的无向图G,至少要添加几条边才能使所给无向图图变成边双连通图。

    先把边双缩成点,然后把叶子连起来即可

    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define maxn 5002 
    using namespace std;
    int n,m,head[maxn],tot=1,t1,t2;
    int dfn[maxn],low[maxn],sc,zh[maxn],top,dy[maxn],cnt;
    int in[maxn];
    bool ins[maxn];
    struct node
    {
    	int v,nex,bri;
    }e[20002];
    void lj(int t1,int t2){
    	e[++tot].v=t2;e[tot].nex=head[t1];head[t1]=tot;
    }
    void tarjan(int k,int fa){
    	dfn[k]=low[k]=++sc;
    	zh[++top]=k,ins[k]=1;
    	for(int i=head[k];i;i=e[i].nex){
    		if(e[i].v==fa)continue;//important
    		if(!dfn[e[i].v]){
    			tarjan(e[i].v,k);
    			low[k]=min(low[k],low[e[i].v]);
    			if(low[e[i].v]>dfn[k]){
    				e[i].bri=e[i^1].bri=1;
    			}
    		}
    		else if(ins[e[i].v]){
    			low[k]=min(low[k],dfn[e[i].v]);
    		}
    	}
    	if(dfn[k]==low[k]){
    		cnt++;
    		while(top>0){
    			dy[zh[top]]=cnt;
    			ins[zh[top]]=0;
    			if(zh[top]==k){top--;break;}
    			top--;
    		}
    	}
    }
    void Q()
    {
    	tot=1;top=cnt=sc=0;
    	for(int i=1;i<=5000;i++)dfn[i]=low[i]=dy[i]=in[i]=0;
    	memset(e,0,sizeof e);
    
    }
    int main(){
    	while(~scanf("%d%d",&n,&m)){
    		Q();
    		for(int i=1;i<=m;i++){
    			scanf("%d%d",&t1,&t2);
    			lj(t1,t2);lj(t2,t1);
    		}
    		for(int i=1;i<=n;i++)
    		{
    			if(!dfn[i])tarjan(i,0);
    		}
    		for(int i=1;i<=tot;i++){
    			if(e[i].bri==1)in[dy[e[i].v]]++;
    		}
    		int sum=0;
    		for(int i=1;i<=cnt;i++)if(in[i]==1)sum++;
    		cout<<(sum+1)/2<<endl;
    	}
        return 0;
    }

    6.2-set

    https://blog.csdn.net/liankewei123456/article/details/81627791 裸题

    POJ 2723 Get Luffy Out

    有n对钥匙,m个门,每对钥匙用了其中1个,另一个就会消失,每个门上有m个锁,用特定的钥匙打开其中1个锁,另一个锁会消失,连续的打开门,问你之多能打开几扇门?

    二分门数,2-set判断是否合法

    为什么只有我2-set写dfs

    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #define maxn 25002 
    using namespace std;
    int n,m,head[maxn],tot,l,r,mid,t1,t2,zh[maxn],top;
    bool mark[maxn];
    struct node{
    	int v,nex;
    }e[3000002];
    struct no{
    	int x,y;
    }key[maxn],d[maxn];
    void lj(int t1,int t2){
    	e[++tot].v=t2;e[tot].nex=head[t1];head[t1]=tot;
    }
    void Q(){
    	tot=0;
    	for(int i=1;i<=25000;i++)mark[i]=head[i]=0;
    }
    bool dfs(int k)
    {
    	if(mark[k])return 1;
    	if(mark[k^1])return 0;
    	mark[k]=1;zh[++top]=k;
    	for(int i=head[k];i;i=e[i].nex){
    		if(!dfs(e[i].v))return 0;
    	}
    	return 1;
    }
    bool pd(int k){
    	Q();
    	for(int i=1;i<=n;i++){
    		t1=2*key[i].x+1,t2=2*key[i].y;
    		lj(t1,t2);
    		t1=2*key[i].y+1,t2=2*key[i].x;
    		lj(t1,t2);
    	}
    	for(int i=1;i<=k;i++){
    		t1=2*d[i].x,t2=2*d[i].y+1;
    		lj(t1,t2);
    		t1=2*d[i].y,t2=2*d[i].x+1;
    		lj(t1,t2);
    	}
    	for(int i=1;i<=n;i++){
    		t1=i*2,t2=i*2+1;
    		if(!mark[t1]&&!mark[t2]){
    			top=0;
    			if(!dfs(t1)){
    				while(top>0){
    					mark[zh[top--]]=0;
    				}
    				if(!dfs(t2))return 0;
    			}
    		}
    	}
    	return 1;
    }
    int main(){
    	while(~scanf("%d%d",&n,&m)&&n){
    		for(int i=1;i<=n;i++){
    			scanf("%d%d",&key[i].x,&key[i].y);
    			key[i].x++,key[i].y++;
    		}
    		for(int i=1;i<=m;i++){
    			scanf("%d%d",&d[i].x,&d[i].y);
    			d[i].x++;d[i].y++;
    		}
    		int l=0,r=m;
    		while(l<r){
    			mid=(l+r+1)/2;
    			if(pd(mid))l=mid;
    			else r=mid-1;
    		}
    		printf("%d
    ",l);
    	}
    	return 0;
    }

    7.dijstra+heap

    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #define maxn 10005
    #define inf 1e9
    using namespace std;
    int n,m,kk,head[maxn],t1,t2,t3,tot;
    int d[maxn][22],flag[maxn][22];
    struct node{
        int v,nex,w;
    }e[100005];
    struct no{
        int x,num,dist;
    };
    bool operator <(no a,no b){
      return a.dist>b.dist;
    } priority_queue<no>q; void lj(int t1,int t2,int t3){ e[++tot].v=t2;e[tot].w=t3;e[tot].nex=head[t1],head[t1]=tot; } int main() { cin>>n>>m>>kk; for(int i=1;i<=m;i++){ scanf("%d%d%d",&t1,&t2,&t3); lj(t1,t2,t3);lj(t2,t1,t3); } for(int i=1;i<=n;i++) for(int j=0;j<=kk;j++)d[i][j]=inf; q.push((no){1,0,0});d[1][0]=0; while(!q.empty()){ no k=q.top();q.pop(); while(flag[k.x][k.num]&&!q.empty())k=q.top(),q.pop(); if(flag[k.x][k.num]&&q.empty())break; flag[k.x][k.num]=1; for(int i=head[k.x];i;i=e[i].nex){ if(d[e[i].v][k.num]>d[k.x][k.num]+e[i].w&&!flag[e[i].v][k.num]){ d[e[i].v][k.num]=d[k.x][k.num]+e[i].w; q.push((no){e[i].v,k.num,d[e[i].v][k.num]}); } if(k.num+1<=kk&&d[e[i].v][k.num+1]>d[k.x][k.num]&&!flag[e[i].v][k.num+1]){ d[e[i].v][k.num+1]=d[k.x][k.num]; q.push((no){e[i].v,k.num+1,d[e[i].v][k.num+1]}); } } } int ans=1e9; for(int i=0;i<=kk;i++)ans=min(ans,d[n][i]); cout<<ans<<endl; return 0; }

    注意判定条件 T.dist<dist

  • 相关阅读:
    XSS的原理分析与解剖:第四章(编码与绕过)*******************未看**********************
    XSS的原理分析与解剖:第三章(技巧篇)**************未看*****************
    XSS的原理分析与解剖(第二篇)
    XSS的原理分析与解剖
    sqlmap用户手册详解【实用版】
    mysql注入篇
    MySQL中函数CONCAT及GROUP_CONCAT
    access注入篇+sqlmap
    搭建本地 8.8 W 乌云漏洞库
    fiddler对浏览器、app抓包及证书安装
  • 原文地址:https://www.cnblogs.com/liankewei/p/10358859.html
Copyright © 2011-2022 走看看