zoukankan      html  css  js  c++  java
  • tarjan算法

    tarjan算法

    记1月9日至1月17日,tarjan算法暂时告一段落。

    个人体会:

    主要功能其一:求解连通分量,将图转化成树。树的特性很多,利用树的特性解题。

    主要功能其二:求出并理解桥和割点,掌握生成和消除桥或割点的方法,算答案或算贡献。

    算法能用的东西不多,但写题的过程还是很欢乐的,代码不长不短,解题要些思维。

    放上几个板子:

    tarjan求强连通分量(缩点)

    #include<iostream>
    #include<stack>
    #include<vector>
    #include<cstring>
    using namespace std;
    #define ll long long
    ll n,m,a[10007],u,v;
    ll dfn[10007],low[10007],vis[10007],sum[10007],pos[10007],cnt;
    ll dp[10007];
    stack<ll>sa;
    vector<ll>ho[10007];
    vector<ll>aq[10007];
    void dfs(ll p){
    	dfn[p]=low[p]=++cnt;
    	sa.push(p);
    	vis[p]=1;
    	for(int i=0;i<ho[p].size();i++){
    		ll to=ho[p][i];
    		if(dfn[to]==0){
    			dfs(to);
    			low[p]=min(low[p],low[to]);
    		}
    		else if(vis[to]==1){
    			low[p]=min(low[p],dfn[to]);
    		}
    	}
    	if(low[p]==dfn[p]){
    		while(!sa.empty()){
    			ll now=sa.top();
    			sa.pop();
    			vis[now]=0;
    			aq[p].push_back(now);
    			sum[p]+=a[now];
    			pos[now]=p;
    			if(now==p){
    				break;
    			}
    		}
    	}
    }
    ll fin(ll p){
    	ll res=0;
    	if(dp[p]!=-1){
    		return dp[p];
    	}
    	for(int i=0;i<aq[p].size();i++){
    		ll now=aq[p][i];
    		for(int j=0;j<ho[now].size();j++){
    			ll to=pos[ho[now][j]];
    			if(pos[to]!=pos[p]){
    				res=max(res,fin(to));
    			}
    		}
    	}
    	return dp[p]=res+sum[p];
    }
    int main(){
    	scanf("%lld%lld",&n,&m);
    	for(int i=1;i<=n;i++){
    		scanf("%lld",&a[i]);
    	}
    	for(int i=1;i<=m;i++){
    		scanf("%lld%lld",&u,&v);
    		ho[u].push_back(v);
    	}
    	for(int i=1;i<=n;i++){
    		if(dfn[i]==0){
    			dfs(i);
    		}
    	}
    	ll ans=0;
    	memset(dp,-1,sizeof(dp));
    	for(int i=1;i<=n;i++){
    		ans=max(ans,fin(pos[i]));
    	}
    	printf("%lld
    ",ans);
    }
    

    tarjan求桥

    #include<iostream>
    #include<algorithm>
    #include<vector>
    using namespace std;
    #define ll long long
    ll n,m,u,v;
    ll dfn[100007],low[100007],cnt;
    vector<ll>ho[100007];
    vector<pair<ll,ll> >ans;
    void tarjan(ll p,ll f){
    	dfn[p]=low[p]=++cnt;
    	for(int i=0;i<ho[p].size();i++){
    		ll to=ho[p][i];
    		if(to==f)continue;
    		if(dfn[to]==0){
    			tarjan(to,p);
    			low[p]=min(low[p],low[to]);
    			if(low[to]>dfn[p]){
    				ans.push_back({min(to,p),max(p,to)});
    			}
    		}
    		else{
    			low[p]=min(low[p],dfn[to]);
    		}
    	}
    
    }
    void init(){
    	ans.clear();
    	cnt=0;
    	for(int i=0;i<n;i++){
    		ho[i].clear();
    		dfn[i]=low[i]=0;
    	}
    }
    int main(){
    	while(~scanf("%lld",&n)){
    		init();
    		for(int i=1;i<=n;i++){
    			char ch;
    			scanf("%lld (%lld)",&u,&m);
    			while(m--){
    				scanf(" %lld",&v);
    				if(u>=v)continue;
    				ho[u].push_back(v);
    				ho[v].push_back(u);
    			}
    		}
    		for(int i=0;i<n;i++){
    			if(dfn[i]==0){
    				tarjan(i,-1);
    			}
    		}
    		sort(ans.begin(),ans.end());
    		printf("%d critical links
    ",ans.size());
    		for(int i=0;i<ans.size();i++){
    			printf("%lld - %lld
    ",ans[i].first,ans[i].second);
    		}puts("");
    	}
    	return 0;
    }
    

    tarjan求割点

    #include<iostream>
    #include<vector>
    #include<set>
    using namespace std;
    #define ll long long
    ll n,u,v;
    ll dfn[107],low[107],cnt;
    vector<ll>ho[107];
    set<ll>sa;
    void tarjan(ll p,ll k){
    	ll tot=0;
    	dfn[p]=low[p]=++cnt;
    	for(int i=0;i<ho[p].size();i++){
    		ll to=ho[p][i];
    		if(dfn[to]==0){
    			tot++;
    			tarjan(to,0);
    			low[p]=min(low[p],low[to]);
    			if(low[to]>=dfn[p]&&k==0){
    				sa.insert(p);
    			}
    		}
    		else{
    			low[p]=min(low[p],dfn[to]);
    		}
    	}
    	if(k==1&&tot>=2){
    		sa.insert(p);
    	}
    }
    int main(){
    	while(~scanf("%lld",&n)){
    		if(n==0)break;
    		sa.clear();
    		for(int i=1;i<=n;i++){
    			ho[i].clear();
    			dfn[i]=0;
    			low[i]=0;
    			cnt=0;
    		}
    		while(1){
    			scanf("%lld",&u);
    			if(u==0)break;
    			while(1){
    				scanf("%lld",&v);
    				ho[u].push_back(v);
    				ho[v].push_back(u);
    				if(getchar()=='
    '){
    					break;
    				}
    			}
    		}
    		for(int i=1;i<=n;i++){
    			if(dfn[i]==0){
    				tarjan(i,1);
    			}
    		}
    		printf("%lld
    ",sa.size());
    	}
    }
    

    tarjan求双连通分量

    #include<iostream>
    #include<algorithm>
    #include<vector>
    #include<stack>
    using namespace std;
    #define ll long long
    ll n,m,u,v,a[500007];
    ll dfn[500007],low[500007],pos[500007],ans[500007],cnt;
    vector<ll>ho[500007];
    vector<ll>aq[500007];
    vector<ll>ans2;
    stack<ll>sa;
    void tarjan(ll p,ll f){
    	dfn[p]=low[p]=++cnt;
    	sa.push(p);
    	for(int i=0;i<ho[p].size();i++){
    		ll to=ho[p][i];
    		if(to==f)continue;
    		if(dfn[to]==0){
    			tarjan(to,p);
    			low[p]=min(low[p],low[to]);
    		}
    		else{
    			low[p]=min(low[p],dfn[to]);
    		}
    	}
    	if(low[p]==dfn[p]){
    		while(!sa.empty()){
    			ll lin=sa.top();
    			sa.pop();
    			pos[lin]=p;
    			ans[p]^=a[lin];//一个双连通分量的权值异或和
    			aq[p].push_back(lin);
    			if(lin==p){
    				break;
    			}
    		}
    	}
    }
    int main(){
    	scanf("%lld%lld",&n,&m);
    	for(int i=1;i<=n;i++){
    		scanf("%lld",&a[i]);
    	}
    	for(int i=1;i<=m;i++){
    		scanf("%lld%lld",&u,&v);
    		ho[u].push_back(v);
    		ho[v].push_back(u);
    	}
    	for(int i=1;i<=n;i++){
    		if(dfn[i]==0){
    			tarjan(i,0);
    		}
    	}
    	for(int i=1;i<=n;i++){
    		if(pos[i]!=i)continue;
    		else{
    			ans2.push_back(ans[i]);
    		}
    	}
    	sort(ans2.begin(), ans2.end());
    	for(int i=0;i<ans2.size();i++){
    		printf("%lld
    ",ans2[i]);
    	}
    }
    
  • 相关阅读:
    Python函数
    Python的集合框架
    go的相关用法
    如何完整反编译AndroidMainfest.xml
    英语中时间的表达方法
    3. vue脚手架安装 express 框架使用 vue框架 weiUI
    2. TypeScript笔记
    基于SignalR的消息推送与二维码描登录实现
    MVC-Model数据注解(三)-Remote验证的一个注意事项
    MVC Remote属性验证
  • 原文地址:https://www.cnblogs.com/whitelily/p/14289959.html
Copyright © 2011-2022 走看看