zoukankan      html  css  js  c++  java
  • 拓扑排序

    拓扑排序

    只针对DAG排序

    如果有环,序列长度不为(n)

    时间复杂度(O(n+m))

    实现:

    维护每个点入度,入度为(0)的入队,每次取队首遍历出边,入度(-1),然后继续让入度为(0)的入队,直到队空

    最长路

    注意(vis)(x)才能更新(y)

    #include <queue>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    typedef long long ll;
    const int N=1e5+10;
    inline int read() {
    	int x=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    	return f*x;
    }
    inline void Max(ll &x,ll y){if(x<y)x=y;}
    int n,m,du[N];
    int hd[N],to[N<<1],tot,nxt[N<<1],w[N<<1];
    inline void add(int x,int y,int z) {
    	to[++tot]=y;w[tot]=z;nxt[tot]=hd[x];hd[x]=tot;
    } 
    queue<int>q;
    ll f[N];
    bool vis[N];
    int main() {
    	n=read();m=read();
    	for(int i=1;i<=m;i++) {
    		int u=read(),v=read(),w=read();
    		add(u,v,w);
    		du[v]++;
    	}
    	for(int i=1;i<=n;i++) 
    		if(!du[i])
    			q.push(i);
    	f[n]=-1;vis[1]=1;
    	while(q.size()) {
    		int x=q.front();q.pop();
    		for(int i=hd[x];i;i=nxt[i]) {
    			int y=to[i];
    			if(vis[x]) {
    				Max(f[y],f[x]+w[i]);
    				vis[y]=1;
    			}
    			if(!--du[y]) q.push(y);
    		}
    	}
    	printf("%lld",f[n]);
    	return 0;
    }
    

    排序

    很多细节

    首先(n)很小,我们可以每次输入一个就拓扑一次

    对于三种情况

    1.如果 没有点入度为(0),这说明有环,矛盾

    如果排出序的点个数不等于已知的点,说明有环,那么显然矛盾;

    2.然后除了情况1,并且入队的点(=n),那么可以排序

    3.除了上面两个就是无法排序咯——wrong 和 ok 判断如果多个点入度为0,那么我们无法确定顺序

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<vector>
    #include<algorithm>
    #include<utility>
    #include<queue>
    using namespace std;
    #define N 150
    vector<int> g[N];
    queue<int> q;
    bool vis[N],wrong,ok;
    int in[N],a[N],inc[N];
    int cnt,sum; 
    int n,m;
    char ch;
    int tp(){
    	wrong=0;sum=0;ok=0;//ok和wrong 判断是否有多个入度为0的,无法确定顺序
    	for(int i=1;i<=26;i++) {
    		inc[i]=in[i];
    		if(!inc[i]&&vis[i]) {
    			if(!ok) ok=1;
    			else wrong=1;
    			q.push(i);
    			a[++sum]=i;
    		}
    	}
    	if(q.empty()) return 1;
    	while(q.size()) {
    		int x=q.front();q.pop();
    		ok=0;
    		for(int i=0;i<g[x].size();i++) {
    			int v=g[x][i];inc[v]--;
    			if(!inc[v]) {
    				q.push(v);a[++sum]=v;
    				if(!ok) ok=1;
    				else wrong=1;
    			}
    		}
    	}
    	if(cnt!=sum) return 1;
    	if(wrong) return 2;
    	return 0;
    }
    int main() {
    	scanf("%d%d",&n,&m);
    	for(int i=1,x,y;i<=m;i++) {
    		cin>>ch; x=ch-64;
    		if(!vis[x]){vis[x]=1;cnt++;}
    		cin>>ch;
    		cin>>ch; y=ch-64;
    		if(!vis[y]){vis[y]=1;cnt++;}
    
    		g[x].push_back(y);
    		in[y]++;
    
    		if(tp()==1) {
    			printf("Inconsistency found after %d relations.",i);
    			return 0;
    		}
    		if(sum==n&&!tp()) {
    			printf("Sorted sequence determined after %d relations: ",i);
    			for(int j=1;j<=n;j++)
    				printf("%c",a[j]+64);
    			printf(".");
    			return 0;
    		}
    	}
    	printf("Sorted sequence cannot be determined.");
    	return 0;
    }
    

    车站分级

    解析:未停靠点向已停靠点连边,然后逐层删点删边,统计层数,最后减(1)

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define N 1005
    using namespace std;
    int in[N],n,m,s;
    int tp[N][N],a[N],b[N],cnt,ans=0;
    bool vis[N],is[N];
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++){
            scanf("%d",&s);
            memset(is,0,sizeof(is));
            for(int j=1;j<=s;j++)
                scanf("%d",&a[j]),is[a[j]]=1;
            for(int j=a[1];j<=a[s];j++)
                if(!is[j])
                    for(int k=1;k<=s;k++)
                        if(!tp[j][a[k]])
                            tp[j][a[k]]=1,in[a[k]]++;
        }
        do{//cnt是点,b[cnt]是车站号
            cnt=0;
            for(int i=1;i<=n;i++)
                if(!in[i]&&!vis[i])
                    vis[i]=1,b[++cnt]=i;
            for(int i=1;i<=cnt;i++)
                for(int j=1;j<=n;j++)
                    if(tp[b[i]][j])
                        tp[b[i]][j]=0,in[j]--;
            ans++;
        }while(cnt);
        printf("%d",ans-1);
        return 0;
    }
    

    骑士bzoj1471

    dp+拓扑

    [设f[i][j]表示一个走到i,另一个走到j的方案数\ 边界 f[a1][b1]=1;目标 f[a2][b2]\ 然后把图拓扑排序,对于每个点,1~n暴力枚举可以到达的点,方案数累加\ 注意两维都要更新 ]

    #include<iostream>
    #include<cstdio>
    #include<queue>
    #include<cstring>
    #define N 205
    #define M 10005
    using namespace std;
    int in[N],n,m;
    long long f[N][N];
    int hd[M],nxt[M],to[M],tot;
    inline void add(int x,int y){
        to[++tot]=y;nxt[tot]=hd[x];hd[x]=tot;
    }
    queue<int>q;
    int a1,a2,b1,b2;
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1,x,y;i<=m;i++){
            scanf("%d%d",&x,&y);
            add(x,y); 
            in[y]++;
        }
        scanf("%d%d%d%d",&a1,&a2,&b1,&b2);
        for(int i=1;i<=n;i++)
            if(!in[i]) q.push(i);
        
        f[a1][b1]=1;
        while(!q.empty()){
            int x=q.front();q.pop();
            for(int i=hd[x];i;i=nxt[i]){
                int y=to[i];
                for(int j=1;j<=n;j++)
                    if(j!=y){
                        f[j][y]+=f[j][x];
                        f[y][j]+=f[x][j];
                    }
                if(--in[y]==0) q.push(y);
            }
        }
        printf("%lld
    ",f[a2][b2]);
        return 0;
    }
    

    菜肴制作

    建反图——最大字典序

    队列代替堆

    #include <queue>
    #include <cstdio>
    #include <vector>
    #include <utility>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    typedef long long ll;
    const int N=2005;
    const int M=10005;
    inline int read() {
    	int x=0;char ch=getchar();
    	while(ch<'0'||ch>'9')ch=getchar();
    	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    	return x;
    }
    inline void Max(int &x,int y){if(x<y)x=y;}
    inline void Min(int &x,int y){if(x>y)x=y;}
    int n,m;
    int du[N],k[N];
    vector<int>G[N];
    
    int tmp[N],st[N],tp;
    #define MP make_pair
    
    void topo() {
    	priority_queue< pair<int,int> >q;
    	memcpy(tmp,du,sizeof(tmp));
    	for(int i=1;i<=n;i++)
    		if(!tmp[i]) q.push(MP(k[i],i));
    	while(q.size()) {
    		int x=q.top().second;q.pop();
    		st[++tp]=x;
    		for(auto y:G[x]) 
    			if(!--tmp[y]) q.push(MP(k[y],y));
    	}
    }
    int work(int now) {
    	priority_queue< pair<int,int> >q;
    	int cnt=0;
    	memcpy(tmp,du,sizeof(tmp));
    	for(int i=1;i<=n;i++)
    		if(!tmp[i]) q.push(MP(k[i],i));
    	while(q.size()) {
    		int x=q.top().second;q.pop();
    		if(x==now) continue;
    		//先不要让他入列,直到别的都拓扑的不能再拓扑了 
    		if(n-cnt>k[x]) return n-cnt;
    		cnt++;
    		for(auto y:G[x]) 
    			if(!--tmp[y]) q.push(MP(k[y],y));
    	}	
    	return n-cnt;
    }
    int main() {
    	n=read();m=read(); 
    	for(int i=1;i<=n;i++) k[i]=read();
    	int x,y;
    	for(int i=1;i<=m;i++) {
    		x=read();y=read();
    		G[y].push_back(x);
    		du[x]++;
    	}
    	topo();
    	for(int i=n;i;i--)
    		printf("%d ",st[i]);
    	puts("");
    	for(int i=1;i<=n;i++)
    		printf("%d ",work(i));
    	return 0;
    }
    
    

    航空管制

    同上

    #include <queue>
    #include <cstdio>
    #include <vector>
    #include <utility>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    typedef long long ll;
    const int N=2005;
    const int M=10005;
    inline int read() {
    	int x=0;char ch=getchar();
    	while(ch<'0'||ch>'9')ch=getchar();
    	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    	return x;
    }
    inline void Max(int &x,int y){if(x<y)x=y;}
    inline void Min(int &x,int y){if(x>y)x=y;}
    int n,m;
    int du[N],k[N];
    vector<int>G[N];
    
    int tmp[N],st[N],tp;
    #define MP make_pair
    
    void topo() {
    	priority_queue< pair<int,int> >q;
    	memcpy(tmp,du,sizeof(tmp));
    	for(int i=1;i<=n;i++)
    		if(!tmp[i]) q.push(MP(k[i],i));
    	while(q.size()) {
    		int x=q.top().second;q.pop();
    		st[++tp]=x;
    		for(auto y:G[x]) 
    			if(!--tmp[y]) q.push(MP(k[y],y));
    	}
    }
    int work(int now) {
    	priority_queue< pair<int,int> >q;
    	int cnt=0;
    	memcpy(tmp,du,sizeof(tmp));
    	for(int i=1;i<=n;i++)
    		if(!tmp[i]) q.push(MP(k[i],i));
    	while(q.size()) {
    		int x=q.top().second;q.pop();
    		if(x==now) continue;
    		//先不要让他入列,直到别的都拓扑的不能再拓扑了 
    		if(n-cnt>k[x]) return n-cnt;
    		cnt++;
    		for(auto y:G[x]) 
    			if(!--tmp[y]) q.push(MP(k[y],y));
    	}	
    	return n-cnt;
    }
    int main() {
    	n=read();m=read(); 
    	for(int i=1;i<=n;i++) k[i]=read();
    	int x,y;
    	for(int i=1;i<=m;i++) {
    		x=read();y=read();
    		G[y].push_back(x);
    		du[x]++;
    	}
    	topo();
    	for(int i=n;i;i--)
    		printf("%d ",st[i]);
    	puts("");
    	for(int i=1;i<=n;i++)
    		printf("%d ",work(i));
    	return 0;
    }
    
    
  • 相关阅读:
    ubuntu18 升级cmake
    开源镜像站汇总
    ubuntu18安装go
    tendermint框架及Tx执行流程
    常用python内置函数
    根据列号返回列名
    Valid Number
    Remove Duplicates from Sorted List II
    vector排序问题<unresolved overloaded function type>
    Spiral Matrix
  • 原文地址:https://www.cnblogs.com/ke-xin/p/13568236.html
Copyright © 2011-2022 走看看