zoukankan      html  css  js  c++  java
  • 洛谷 [P2661] 信息传递

    求有向图的权值为一的最小环##

    并查集做法####

    维护一个dis[],表示i号元素到fa[i]的距离。
    对于输入的每两个点u,v,询问这两个点的fa[]是否相同,如果相同就成环,维护最小值,mi=min(mi,dis[u]+dis[v]+1)。如果不相同,merge(u,v)。目测是最简单的做法。
    但是只适用于权值为一的边。
    注意对于一条U指向v的边,是将u合并到v上。

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    const int MAXN=200005;
    int read(){
    	int rv=0,fh=1;
    	char c=getchar();
    	while(c<'0'||c>'9'){
    		if(c=='-') fh=-1;
    		c=getchar();
    	}
    	while(c>='0'&&c<='9'){
    		rv=(rv<<1)+(rv<<3)+c-'0';
    		c=getchar();
    	}
    	return rv*fh;
    }
    int fa[MAXN],n,mi=0x7fffffff/3,dis[MAXN];
    int find(int x){
    	if(x!=fa[x]) {
    		int t=fa[x];fa[x]=find(fa[x]);dis[x]+=dis[t];
    	}
    	return fa[x];
    }
    void merge(int x,int y){
    	int r1=find(x),r2=find(y);
    	if(r1!=r2){
    		fa[r1]=r2;
    		dis[x]=dis[y]+1;
    	}
    }
    int main(){
    	freopen("in.txt","r",stdin);
    	n=read();
    	for(int i=1;i<=n;i++){
    		fa[i]=i;
    	}
    	for(int i=1;i<=n;i++){
    		int t=read();
    		if(find(i)==find(t)){
    			mi=min(mi,dis[i]+dis[t]+1);
    		}else {
    			merge(i,t);
    		}
    	}
    	cout<<mi;
    	fclose(stdin);
    	return 0;
    }
    
    

    topsort####

    使用拓扑排序删掉那些一定不属于环上的点,再用dfs更新最小环的数量。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <algorithm>
    #include <cmath>
    #include <queue>
    using namespace std;
    const int MAXN=200005;
    int read(){
    	int rv=0,fh=1;
    	char c=getchar();
    	while(c<'0'||c>'9'){
    		if(c=='-') fh=-1;
    		c=getchar();
    	}
    	while(c>='0'&&c<='9'){
    		rv=(rv<<1)+(rv<<3)+c-'0';
    		c=getchar();
    	}
    	return rv*fh;
    }
    struct edge{
    	int to,nxt;
    }e[MAXN];
    int n,head[MAXN],nume,in[MAXN],f[MAXN],mi=0x7fffffff/3,cnt;
    void adde(int from,int to){
    	e[++nume].to=to;
    	e[nume].nxt=head[from];
    	head[from]=nume;
    }
    queue<int> q;
    void dfs(int u){
    	cnt++;
    	f[u]=1;
    	for(int i=head[u];i;i=e[i].nxt){
    		int v=e[i].to;
    		if(!f[v]) dfs(v);
    	}
    }
    int main(){
    	freopen("in.txt","r",stdin);
    	n=read();
    	for(int i=1;i<=n;i++){
    		int t=read();
    		adde(i,t);
    		in[t]++;
    	}
    	for(int i=1;i<=n;i++){
    		if(!in[i]){
    			q.push(i),f[i]=1;
    		}
    	}
    	while(!q.empty()){
    		int u=q.front();q.pop();
    		for(int i=head[u];i;i=e[i].nxt){
    			int v=e[i].to;
    			in[v]--;
    			if(!in[v]&&!f[v]){
    				q.push(v);f[v]=1;
    			}
    		}
    	}
    	for(int i=1;i<=n;i++){
    		cnt=0;
    		if(!f[i]) {dfs(i);mi=min(mi,cnt);}
    		
    	}
    	cout<<mi;
    	fclose(stdin);
    	return 0;
    }
    
    

    tarjan求强连通分量####

    最小环即强连通分量

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <algorithm>
    #include <cmath>
    #include <queue>
    #include <stack>
    using namespace std;
    const int MAXN=200005;
    int read(){
    	int rv=0,fh=1;
    	char c=getchar();
    	while(c<'0'||c>'9'){
    		if(c=='-') fh=-1;
    		c=getchar();
    	}
    	while(c>='0'&&c<='9'){
    		rv=(rv<<1)+(rv<<3)+c-'0';
    		c=getchar();
    	}
    	return rv*fh;
    }
    struct edge{
    	int to,nxt;
    }e[MAXN];
    int n,head[MAXN],nume,dfn[MAXN],low[MAXN],in,mi=0x7fffffff/3;
    stack <int>s;
    bool f[MAXN];
    void adde(int from,int to){
    	e[++nume].to=to;
    	e[nume].nxt=head[from];
    	head[from]=nume;
    }
    void tarjan(int u){
    	dfn[u]=++in;
    	low[u]=++in;
    	f[u]=1;
    	s.push(u);
    	for(int i=head[u];i;i=e[i].nxt){
    		int v=e[i].to;
    		if(!dfn[v]){
    			tarjan(v);
    			low[u]=min(low[u],low[v]);
    		}else if(f[v]){
    			low[u]=min(low[u],dfn[v]);
    		}
    	}
    	if(dfn[u]==low[u]){
    		int v=0;
    		int cnt=0;
    		do{
    			v=s.top();
    			s.pop();
    			f[v]=0;
    			cnt++;
    		}while(v!=u);
    		mi=min(mi,cnt);
    	//	cout<<u<<" "<<cnt<<endl;
    	}
    }
    int main(){
    	freopen("in.txt","r",stdin);
    	n=read();
    	for(int i=1;i<=n;i++){
    		int t=read();
    		adde(i,t);
    	}
    	for(int i=1;i<=n;i++){
    		if(!dfn[i]) tarjan(i);
    	}
    	cout<<mi;
    	fclose(stdin);
    	return 0;
    }
    
    
  • 相关阅读:
    10、xsl中import用法
    09、xsl中输出对应的列和值
    08、xsl中操作子节点带循环输出
    07、xsl中操作子节点
    06、xsl中choose进行多条件选择
    05、xsl中IF的用法
    04、xsl中对字段进行排序
    03、xsl中添加筛选条件
    02、xsl的for循环输出
    01、xsl样式表用网页输出
  • 原文地址:https://www.cnblogs.com/Mr-WolframsMgcBox/p/7868331.html
Copyright © 2011-2022 走看看