北京化工大学数据结构2022/11/17作业 题解

(7条消息) 食用前须知(阅读并同意后在食用其他部分)_lxrrrrrrrr的博客-CSDN博客

看完进来哈

目录

问题 A: 邻接矩阵存储的图,节点的出度和入度计算(附加代码模式)

问题 B: 算法7-12:有向无环图的拓扑排序

问题 C: 有向图是否存在环?

问题 D: 是否为有效的拓扑序列

问题 E: 案例6-2.6:最短工期

---------------------------------------概念-----------------------------------------

最早发生时间:

最迟发生时间:

关键路径:

--------------------------------------------------------------------------------------

问题 F: 图-节点的最早发生时间

问题 G: 图-节点的最迟发生时间

问题 H: 图-边的最早发生时间

问题 I: 图-边的最迟发生时间

问题 J: 图-图的关键路径


问题 A: 邻接矩阵存储的图,节点的出度和入度计算(附加代码模式)

模拟即可

#include 
using namespace std;
#define MAX_SIZE 200
struct Graph{
    int nodeNumber;
    int adjMatrix[MAX_SIZE][MAX_SIZE];
};
void CalculateDegree(const Graph& g,int inDegree[],int outDegree[]){
    int n=g.nodeNumber;
    for(int i=0;i

问题 B: 算法7-12:有向无环图的拓扑排序

拓扑排序板子

从每个入度为0的点开始宽搜即可

#include 
#define int long long
#define pb push_back
#define fer(i,a,b) for(int i=a;i<=b;++i)
#define der(i,a,b) for(int i=a;i>=b;--i)
#define all(x) (x).begin(),(x).end()
#define pll pair
#define et  cout<<'\n'
#define xx first
#define yy second
using namespace std;
const int N=1e6+10;
int G[1000][1000];
int n;
int du[1000];
vector ans;
bool tpst() {
    int num=0;
    stack q;
    fer(i,0,n-1){
        if(du[i]==0){
            q.push(i);
        }
    }
    while(q.size()) {
        int u=q.top();
        q.pop();
        ans.pb(u);
        num++;
        fer(v,0,n-1){
            if(G[u][v]) {
                du[v]--;
                if(du[v]==0)
                    q.push(v);  
            } 
        }
    }
    if(num==n){
        return true;
    }
    else{
        return false;
    }
}
signed main()
{
    cin>>n;
    fer(i,0,n-1){
        fer(j,0,n-1){
            cin>>G[i][j];
            if(G[i][j]){
                du[j]++;
            }
        }
    }
    if(tpst()) {
        for(auto t:ans){
            cout<

问题 C: 有向图是否存在环?

判环的话

并查集好写一点

#include 
#define int long long
#define pb push_back
#define fer(i,a,b) for(int i=a;i<=b;++i)
#define der(i,a,b) for(int i=a;i>=b;--i)
#define all(x) (x).begin(),(x).end()
#define pll pair
#define et  cout<<'\n'
#define xx first
#define yy second
using namespace std;
const int N=1e6+10;
int p[N];
int find(int x){
    if(p[x]!=x)  p[x]=find(p[x]);
    return p[x];
}
 
signed main(){
    int n,m;
    while(cin>>n>>m){
        if(!n && !m) break;
        fer(i,1,n) p[i]=i;
        bool fl=false;
        fer(i,1,m){
            int a,b;
            cin>>a>>b;
            if(find(a)!=find(b)){
                p[find(a)]=find(b);
            }
            else{
                fl=1;
                break;
            }
        }
        if(fl){
            cout<<"YES\n";
        }
        else{
            cout<<"NO\n";
        }
    }
}

问题 D: 是否为有效的拓扑序列

计算一下度数即可

#include 
#define int long long
#define pb push_back
#define fer(i,a,b) for(int i=a;i<=b;++i)
#define der(i,a,b) for(int i=a;i>=b;--i)
#define all(x) (x).begin(),(x).end()
#define pll pair
#define et  cout<<'\n'
#define xx first
#define yy second
using namespace std;
const int N=1e6+10;
vector v[N];
int inv[N];
int now[N];
int n,m;
int inx[N];
bool check(){
    fer(i,0,n) now[i]=inv[i];
    for(int i=0;i>inx[i];
    }
    for(int i=0;i>n>>m;
    fer(i,1,m){
        int a,b;
        cin>>a>>b;
        v[a].pb(b);
        inv[b]++;
    }
    int k;
    cin>>k;
    fer(i,1,k){
        if(check()){
            cout<<"YES"<

问题 E: 案例6-2.6:最短工期

拓扑排序不那么板子的板子题

#include 
#define int long long
#define pb push_back
#define fer(i,a,b) for(int i=a;i<=b;++i)
#define der(i,a,b) for(int i=a;i>=b;--i)
#define all(x) (x).begin(),(x).end()
#define pll pair
#define et  cout<<'\n'
#define xx first
#define yy second
using namespace std;
const int N=1e6+10;
int tmp[N];
int h[N],e[N],ne[N],w[N],idx;
int d[N],ans[N];
queue q;
void add(int a,int b,int f){
    e[idx]=b,w[idx]=f,ne[idx]=h[a],h[a]=idx++;
}
int n,m;
void solve(){
    int ans=0;
    while(!q.empty()){
        int t=q.front();
        q.pop();
        for(int i=h[t];i!=-1;i=ne[i]){
            d[e[i]]--;
            if(d[e[i]]==0) q.push(e[i]);
            tmp[e[i]]=max(tmp[e[i]],w[i]+tmp[t]);
            ans=max(ans,tmp[e[i]]);
        }
    }
    fer(i,0,n-1){
        if(d[i]!=0){
            cout<<"Impossible\n";
            return;
        }
    }
    cout<>n>>m;
    fer(i,1,m){
        int a,b,c;
        cin>>a>>b>>c;
        add(a,b,c);
        d[b]++;
    }
    fer(i,0,n-1){
        if(d[i]==0){
            q.push(i);
            tmp[i]=0;
        }
    }
    solve();
}

---------------------------------------概念-----------------------------------------

北京化工大学数据结构2022/11/17作业 题解_第1张图片

作业上的概念模糊不清,这里稍作解释,是离散数学中的概念

我们以这张图为例

最早发生时间:

从前往后,前驱结点到当前结点所需时间,取最大值。

如上图中的节点4有两个前驱结点(节点2和3),节点2到节点4的最早发生时间是a1+a3也就是8,节点3到节点4的最早发生时间是a2+a4也就是12,因为12>8,所以节点4的最早发生时间是12.

最迟发生时间:

从后往前,后继结点的最迟发生时间-边权值,取最小值。

也就是求一次最早发生时间,再从出度为0的点反向更新回来求出每个点的最迟时间

北京化工大学数据结构2022/11/17作业 题解_第2张图片

关键路径:

最早发生时间和最迟发生时间相同的结点即为关键路径上的节点。

 也就是两个都要求一遍呗

而边的最早最迟发生时间大家看作业上的图就知道了,就是看对应的点的最早最迟发生时间

所以我们可以先求点的然后在遍历一遍求出边的最早最迟发生时间

--------------------------------------------------------------------------------------

下列代码我没有用拓扑排序写

而是直接宽搜的,然后松弛

拓扑排序本质就是bfs呗

因为后续涉及到对边的操作,所以我用了链式前向星存图

不懂可以csdn一下,很简单的

问题 F: 图-节点的最早发生时间

边bfs边更新每个点的答案

#include 
#define int long long
#define pb push_back
#define fer(i,a,b) for(int i=a;i<=b;++i)
#define der(i,a,b) for(int i=a;i>=b;--i)
#define all(x) (x).begin(),(x).end()
#define pll pair
#define et  cout<<'\n'
#define xx first
#define yy second
using namespace std;
const int N=1e6+10;
int h[N],w[N],e[N],ne[N],idx;
void add(int a, int b, int c)
{
    e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++ ;
}
int dist[N];
int n,m;
void bfs(){
    memset(dist,0,sizeof dist);
    dist[1]=0;
    queue q;
    q.push(1);
    while(q.size()){
        auto tp=q.front();
        q.pop();
        for(int i=h[tp];i!=-1;i=ne[i]){
            int j=e[i];
            if(w[i]+dist[tp]>dist[j]){
                dist[j]=dist[tp]+w[i];
                q.push(j);
            }
        }
    }
}
signed main(){
    memset(h,-1,sizeof h);
    cin>>n>>m;
    fer(i,1,m){
        int a,b,w;
        cin>>a>>b>>w;
        add(a+1,b+1,w);
    }
    bfs();
    fer(i,1,n){
        cout<

问题 G: 图-节点的最迟发生时间

我们需要建两张图,一张正向图一张反向图

从第一张图bfs出去求出最早时间,然后在第二张图反向bfs一遍

#include 
#define int long long
#define pb push_back
#define fer(i,a,b) for(int i=a;i<=b;++i)
#define der(i,a,b) for(int i=a;i>=b;--i)
#define all(x) (x).begin(),(x).end()
#define pll pair
#define et  cout<<'\n'
#define xx first
#define yy second
using namespace std;
const int N=1e6+10;
int h[N],w[N],e[N],ne[N],idx;
int h2[N],w2[N],e2[N],ne2[N],idx2;
void add1(int a, int b, int c)
{
    e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++ ;
}
void add2(int a, int b, int c)
{
    e2[idx2]=b,w2[idx2]=c,ne2[idx2]=h2[a],h2[a]=idx2++ ;
}
int dist[N];
int dist2[N];
int n,m;
void bfs(){
    memset(dist,0,sizeof dist);
    dist[1]=0;
    queue q;
    q.push(1);
    while(q.size()){
        auto tp=q.front();
        q.pop();
        for(int i=h[tp];i!=-1;i=ne[i]){
            int j=e[i];
            if(w[i]+dist[tp]>dist[j]){
                dist[j]=dist[tp]+w[i];
                q.push(j);
            }
        }
    }
    memset(dist2,0x3f,sizeof dist2);
    queue q2;
    fer(i,1,n){
        if(h[i]==-1){
            dist2[i]=dist[i];
            q2.push(i);
        }
    }
 
    while(q2.size()){
        auto tp=q2.front();
        q2.pop();
        for(int i=h2[tp];i!=-1;i=ne2[i]){
            int j=e2[i];
            if(dist2[tp]-w2[i]>n>>m;
    fer(i,1,m){
        int a,b,w;
        cin>>a>>b>>w;
        add1(a+1,b+1,w);
        add2(b+1,a+1,w);
    }
    bfs();
    fer(i,1,n){
        cout<

问题 H: 图-边的最早发生时间

和点的最早发生时间一样

这条边是那个点引出来的答案就和这个点的最早发生时间一样

#include 
#define int long long
#define pb push_back
#define fer(i,a,b) for(int i=a;i<=b;++i)
#define der(i,a,b) for(int i=a;i>=b;--i)
#define all(x) (x).begin(),(x).end()
#define pll pair
#define et  cout<<'\n'
#define xx first
#define yy second
using namespace std;
const int N=1e6+10;
int h[N],w[N],e[N],ne[N],idx;
int res[N];
void add(int a, int b, int c)
{
    e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++ ;
}
int dist[N];
int n,m;
void bfs(){
    memset(dist,0,sizeof dist);
    dist[1]=0;
    queue q;
    q.push(1);
    while(q.size()){
        auto tp=q.front();
        q.pop();
        for(int i=h[tp];i!=-1;i=ne[i]){
            int j=e[i];
            if(w[i]+dist[tp]>dist[j]){
                dist[j]=dist[tp]+w[i];
                q.push(j);
            }
        }
    }
}
signed main(){
    memset(h,-1,sizeof h);
    cin>>n>>m;
    fer(i,1,m){
        int a,b,w;
        cin>>a>>b>>w;
        add(a+1,b+1,w);
    }
    bfs();
    fer(node,1,n){
        for(int i=h[node];i!=-1;i=ne[i]){
            res[i]=dist[node];
        }
    }
    fer(i,0,m-1){
        cout<

问题 I: 图-边的最迟发生时间

和点的最迟发生时间一样

这条边指向那个点的答案就是这个点的最迟发生时间减去权值

#include 
#define int long long
#define pb push_back
#define fer(i,a,b) for(int i=a;i<=b;++i)
#define der(i,a,b) for(int i=a;i>=b;--i)
#define all(x) (x).begin(),(x).end()
#define pll pair
#define et  cout<<'\n'
#define xx first
#define yy second
using namespace std;
const int N=1e6+10;
int h[N],w[N],e[N],ne[N],idx;
int h2[N],w2[N],e2[N],ne2[N],idx2;
void add1(int a, int b, int c)
{
    e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++ ;
}
void add2(int a, int b, int c)
{
    e2[idx2]=b,w2[idx2]=c,ne2[idx2]=h2[a],h2[a]=idx2++ ;
}
int dist[N];
int dist2[N];
int n,m;
void bfs(){
    memset(dist,0,sizeof dist);
    dist[1]=0;
    queue q;
    q.push(1);
    while(q.size()){
        auto tp=q.front();
        q.pop();
        for(int i=h[tp];i!=-1;i=ne[i]){
            int j=e[i];
            if(w[i]+dist[tp]>dist[j]){
                dist[j]=dist[tp]+w[i];
                q.push(j);
            }
        }
    }
    memset(dist2,0x3f,sizeof dist2);
    queue q2;
    fer(i,1,n){
        if(h[i]==-1){
            dist2[i]=dist[i];
            q2.push(i);
        }
    }
 
    while(q2.size()){
        auto tp=q2.front();
        q2.pop();
        for(int i=h2[tp];i!=-1;i=ne2[i]){
            int j=e2[i];
            if(dist2[tp]-w2[i]>n>>m;
    fer(i,1,m){
        int a,b,w;
        cin>>a>>b>>w;
        add1(a+1,b+1,w);
        add2(b+1,a+1,w);
    }
    bfs();
    fer(node,1,n){
        for(int i=h[node];i!=-1;i=ne[i]){
            int j=e[i];
            res[i]=dist2[j]-w[i];
        }
    }
    fer(i,0,m-1){
        cout<

问题 J: 图-图的关键路径

两个都求一边

然后看相等

#include 
#define int long long
#define pb push_back
#define fer(i,a,b) for(int i=a;i<=b;++i)
#define der(i,a,b) for(int i=a;i>=b;--i)
#define all(x) (x).begin(),(x).end()
#define pll pair
#define et  cout<<'\n'
#define xx first
#define yy second
using namespace std;
const int N=1e6+10;
int h[N],w[N],e[N],ne[N],idx;
int h2[N],w2[N],e2[N],ne2[N],idx2;
void add1(int a, int b, int c)
{
    e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++ ;
}
void add2(int a, int b, int c)
{
    e2[idx2]=b,w2[idx2]=c,ne2[idx2]=h2[a],h2[a]=idx2++ ;
}
int dist[N];
int dist2[N];
int n,m;
void bfs(){
    memset(dist,0,sizeof dist);
    dist[1]=0;
    queue q;
    q.push(1);
    while(q.size()){
        auto tp=q.front();
        q.pop();
        for(int i=h[tp];i!=-1;i=ne[i]){
            int j=e[i];
            if(w[i]+dist[tp]>dist[j]){
                dist[j]=dist[tp]+w[i];
                q.push(j);
            }
        }
    }
    memset(dist2,0x3f,sizeof dist2);
    queue q2;
    fer(i,1,n){
        if(h[i]==-1){
            dist2[i]=dist[i];
            q2.push(i);
        }
    }
  
    while(q2.size()){
        auto tp=q2.front();
        q2.pop();
        for(int i=h2[tp];i!=-1;i=ne2[i]){
            int j=e2[i];
            if(dist2[tp]-w2[i] edge;
signed main(){
    memset(h,-1,sizeof h);
    memset(h2,-1,sizeof h2);
    cin>>n>>m;
    fer(i,1,m){
        int a,b,w;
        cin>>a>>b>>w;
        edge.push_back({a,b});
        add1(a+1,b+1,w);
        add2(b+1,a+1,w);
    }
    bfs();
    fer(node,1,n){
        for(int i=h[node];i!=-1;i=ne[i]){
            res[i]=dist[node];
        }
    }
    fer(node,1,n){
        for(int i=h[node];i!=-1;i=ne[i]){
            int j=e[i];
            res2[i]=dist2[j]-w[i];
        }
    }
    fer(i,0,m-1){
        if(res[i]==res2[i]){
            cout<"<

你可能感兴趣的:(数据结构)