拓扑排序

问题1.判断有没有环

http://hihocoder.com/problemset/problem/1174

用vector模拟邻接表,开一个记录入度的一维数组,一个存储入度为0的队列

ac代码如下

#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<string.h>
using namespace std;
typedef long long int ll;
int n,k,a,b,t,m;
const int maxn=1e5+5;
vector<int>v[maxn];
queue<int>q;
int indge[maxn];
bool judge()
{
    int num=0;
    while(!q.empty())q.pop();
    for(int i=1;i<=n;i++){
        if(!indge[i])q.push(i);
    }
    while(!q.empty()){
        int tot=q.front();
        q.pop();
        num++;
        for(int i=0;i<v[tot].size();i++){
            if(--indge[v[tot][i]]==0)q.push(v[tot][i]);
        }
    }
    if(num==n)return true;
    else return false;
}
int main()
{
    cin>>t;
    for(int i=1;i<=t;i++){
        cin>>n>>m;
        for(int i=0;i<maxn;i++)v[i].clear();
        memset(indge,0,sizeof(indge));
        for(int j=0;j<m;j++){
            cin>>a>>b;
            v[a].push_back(b);
            indge[b]++;
        }
        if(judge())puts("Correct");
        else puts("Wrong");
    }
    return 0;
}
/*
2
2 2
1 2
2 1
3 2
1 2
1 3
*/

 问题2:给定一个dag图,给定一些点病毒为1,他们为传染给后继结点,依次类推,求最终的病毒数量

http://hihocoder.com/problemset/problem/1175

#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<string.h>
using namespace std;
typedef long long int ll;
int n,k,m,b,t1,t2;
const int maxn=1e5+5;
const int mod=142857;
vector<int>v[maxn];
vector<ll>a(maxn);
queue<int>q;
int indge[maxn];
void res()
{
    while(!q.empty())q.pop();
    for(int i=1;i<=n;i++){
        if(!indge[i])q.push(i);
    }
    while(!q.empty()){
        int tot=q.front();
        q.pop();
        for(int i=0;i<v[tot].size();i++){
                a[v[tot][i]]=(a[v[tot][i]]+a[tot])%mod;
            if(--indge[v[tot][i]]==0){
                q.push(v[tot][i]);
            }
        }
    }
}
int main()
{
    for(int i=0;i<maxn;i++)v[i].clear();a.clear();
    cin>>n>>m>>k;
    for(int i=0;i<k;i++){
        cin>>b;
        a[b]=1;
    }
        memset(indge,0,sizeof(indge));
        for(int j=0;j<m;j++){
            cin>>t1>>t2;
            v[t1].push_back(t2);
            indge[t2]++;
        }
        res();
    long long int ans=0;
    for(int i=1;i<=n;i++){
        ans=(ans+a[i])%mod;//;
    }
    cout<<ans<<endl;
    return 0;
}
/*
2
2 2
1 2
2 1
3 2
1 2
1 3
*/

 洛谷 P4017 最大食物链计数

https://www.luogu.com.cn/problem/P4017

题目是找生产者到最高级消费者的路线有几条。

其实是找入度为0的点到出度为0的路径方式有几种。

预处理入度和出度,拓扑排序,把出度为0的点的路线累加。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<queue>
#include<map>
#include<string.h>
using namespace std;
typedef long long int ll;
int n,k,m,b,t,t1,t2,t3,maxx=0;
const int maxn=1e5+5;
const int mod= 80112002;
vector<int >v[maxn];
vector<int>a(maxn);
queue<int>q;
int indge[maxn];
int outdge[maxn];
void topsort()
{
    int num=0;
    while(!q.empty())q.pop();
    for(int i=1;i<=n;i++){
        if(!indge[i]){
            a[i]=1;
            q.push(i);
        }
    }
    while(!q.empty()){
        int tot=q.front();
        q.pop();
        num++;
        for(int i=0;i<v[tot].size();i++){
            if(--indge[v[tot][i]]==0){
                q.push(v[tot][i]);

            }
            a[v[tot][i]]=(a[v[tot][i]]+a[tot])%mod;
        }
    }
}
int main()
{
        scanf("%d%d",&n,&m);
        for(int i=0;i<maxn;i++)v[i].clear();a.clear();
        memset(indge,0,sizeof(indge));
        memset(outdge,0,sizeof(outdge));
        for(int j=0;j<m;j++){
            //cin>>t1>>t2>>t3;
            scanf("%d%d",&t1,&t2);
            v[t1].push_back(t2);
            indge[t2]++;
            outdge[t1]++;
        }
        topsort();
        int ans=0;
        for(int i=1;i<=n;i++){
            if(outdge[i]==0)ans=(ans+a[i])%mod;
        }
        cout<<ans<<endl;
        return 0;
}

 洛谷 P1807 最长路

https://www.luogu.com.cn/problem/P1807

一道裸的dag拓扑排序加上了权值,vector模拟邻接表存出边和权值,dp数组更新最长路。

/*
 展开
题目描述

设 G 为有 n 个顶点的带权有向无环图,G 中各顶点的编号为 1 到 n,请设计算法,计算图 GG 中 <1,n><1,n> 间的最长路径。

输入格式

输入的第一行有两个整数,分别代表图的点数 n 和边数 m。

第 2 到第 (m+1) 行,每行 3 个整数 u, v,w,代表存在一条从 u 到 v 边权为w的边。

输出格式

输出一行一个整数,代表 1 到 n 的最长路。

若 1 与 n 不联通,请输出 -1。
*/

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e4+5;
int indge[maxn],dp[maxn],bj[maxn];
int n,m;
vector<pair<int,int> >v[maxn];
void topsort()
{
    queue<int>q;
    while(!q.empty())q.pop();
    for(int i=1;i<=n;i++){
        if(!indge[i])q.push(i);
    }
    while(!q.empty()){
        int k=q.front();q.pop();
        for(int i=0;i<v[k].size();i++){
            if(--indge[v[k][i].first]==0)q.push(v[k][i].first);
            if(bj[k]){
                dp[v[k][i].first]=max(dp[v[k][i].first],dp[k]+v[k][i].second);///自身的长度与父亲节点的最长路加上父亲到儿子这条边的长度比较
                bj[v[k][i].first]=1;
             }
        }
    }
}
int main()
{
    cin>>n>>m;
    int a,b,c;
    memset(indge,0,sizeof(indge));
    memset(dp,0,sizeof(dp));
    memset(bj,0,sizeof(bj));
    for(int i=0;i<m;i++){
        cin>>a>>b>>c;
        v[a].push_back(make_pair(b,c));
        indge[b]++;
    }
    dp[n]=-1,bj[1]=1;///初始化dp[n]=-1,输出方便,bj[1]=1,标记1能到达点
    topsort();
    cout<<dp[n]<<endl;
    return 0;
}

 

posted @ 2020-05-15 16:57  mohari  阅读(122)  评论(0编辑  收藏  举报