百❀数据结构10

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

可以用邻接矩阵的方式去存储一个图,要求计算这种方式下每个节点的入度和出度。
 

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#include <iostream>
#include <cstdio>
using namespace std;
 
#define MAX_SIZE 100
 
struct Graph{
    int nodeNumber;
    int adjMatrix[MAX_SIZE][MAX_SIZE];
};
 
// 计算每个节点的出度和入度
void CalculateDegree(const Graph& g, int inDegree[], int outDegree[]){
    for(int i=0;i<g.nodeNumber;i++){
        for(int j=0;j<g.nodeNumber;j++){
            if(g.adjMatrix[i][j]){
                outDegree[i]++;
                inDegree[j]++;
            }
        }
    }
}
/*
// please comment the following code when you submit to OJ
int main(){
    // freopen("/config/workspace/answer/test.in","r",stdin);
    Graph g;
    cin >> g.nodeNumber;
    int inDegree[g.nodeNumber] = {0}, outDegree[g.nodeNumber] = {0};
    for(int i=0;i<g.nodeNumber;i++){
        for(int j=0;j<g.nodeNumber;j++){
            cin >> g.adjMatrix[i][j];
        }
    }
    CalculateDegree(g, inDegree, outDegree);
    for(int i=0;i<g.nodeNumber;i++){
        cout << inDegree[i] << " " << outDegree[i] << endl;
    }
    return 0;
}
*/

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

在本题中,读入一个有向图的邻接矩阵(即数组表示),建立有向图并按照以上描述中的算法判断此图是否有回路,如果没有回路则输出拓扑有序的顶点序列。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int a[105][105];
int n;
vector<int>ans;
int init[1005]={0};
// void dfs(int v){
//     vis[v]=1;
//     for(int i=0;i<n;i++){
//         if(vis[i]&&a[v][i]){
//             fl=0;
//             return;
//         }
//         if(a[v][i]&&!vis[i]){
//             vis[i]=1;
//             dfs(i);
//         }
//     }
// }
bool check(){
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++)
            if(a[i][j]) ++init[j];
    }
    stack<int>q;
    int sum=0;
    for(int i=0;i<n;i++) if(!init[i]) q.push(i);
    while(!q.empty()){
        int v=q.top();q.pop();
        ans.push_back(v);sum++;
        for(int i=0;i<n;i++){
            if(a[v][i]){
                --init[i];
                if(!init[i]) q.push(i);
            } 
        }
    }
    if(sum<n) return 0;
    return 1;
}
int main()
{
    cin>>n;
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++) cin>>a[i][j];
    if(check()){
        for(auto i:ans) cout<<i<<" ";
    }
    else cout<<"ERROR";
    return 0;
}

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

写程序判断有向图是否存在环。有向图的输入用n个二元组表示(u,v),表示从u到v有一条有向边,起点是u,终点是v。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int a[1005][1005];
int n,m;
bool fl=1;
bool vis[1005];
vector<int>ans;
int init[1005]={0};
void dfs(int v){
    //vis[v]=1;
    for(int i=1;i<=n;i++){
        if(vis[i]&&a[v][i]&&i!=v){
            fl=0;
            return;
        }
        if(a[v][i]&&!vis[i]&&i!=v){
            vis[i]=1;
            dfs(i);
        }
    }
}
// bool check(){
//     for(int i=0;i<n;i++){
//         for(int j=0;j<n;j++)
//             if(a[i][j]) ++init[j];
//     }
//     stack<int>q;
//     int sum=0;
//     for(int i=0;i<n;i++) if(!init[i]) q.push(i);
//     while(!q.empty()){
//         int v=q.top();q.pop();
//         ans.push_back(v);sum++;
//         for(int i=0;i<n;i++){
//             if(a[v][i]){
//                 --init[i];
//                 if(!init[i]) q.push(i);
//             } 
//         }
//     }
//     if(sum<n) return 0;
//     return 1;
// }
int main()
{
    while(cin>>n>>m&&(m||n)){
        memset(a,0,sizeof(a));
        memset(init,0,sizeof(init));
        fl=1;
        int x,y;
        for(int i=0;i<m;i++){
             
            cin>>x>>y;
            a[x][y]=1;
        }
        dfs(x);
        if(fl||m==0){
            cout<<"NO"<<endl;
        }
            else cout<<"YES"<<endl;
        }
     
    return 0;
}

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

本题会给出一个图,以及多个序列,你来判断每一个序列是否是该图的有效拓扑序列。

本来想看有没有相关算法的,发现数据小,暴力就完事了。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int a[1005][1005]={0},c[1005][1005];
int n,m;
bool fl=1;
bool vis[1005];
vector<int>ans;
int init[1005]={0},b[1005]={0};
struct node{
    int x,y;
};
vector<int> vc;
void move1(int v){
    for(int i=0;i<m;i++){
        if(a[v][i]&&i!=v) a[v][i]=0;
    }
}
bool look(int v){
    for(int i=0;i<m;i++)
        if(a[i][v]&&i!=v) return false;
    return 1;    
}
bool check(){
    for(int i=0;i<m;i++) cin>>b[i];
    if(!look(b[0])) return false;
    for(int i=0;i<m-1;i++){
        move1(b[i]);
        if(!look(b[i+1])) return false;
    }
    return true;
}
int main()
{
    cin>>m>>n;
    for(int i=0;i<n;i++){
        int x,y;
        cin>>x>>y;
        c[x][y]=1;
        //init[y]++;
    }
         
    int t;
    cin>>t;
    while(t--){
        for(int i=0;i<m;i++) 
            for(int j=0;j<m;j++) a[i][j]=c[i][j];
        if(check()) cout<<"YES"<<endl;
        else cout<<"NO"<<endl;
    }
    return 0;
}

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

一个项目由若干个任务组成,任务之间有先后依赖顺序。项目经理需要设置一系列里程碑,在每个里程碑节点处检查任务的完成情况,并启动后续的任务。现给定一个项目中各个任务之间的关系,请你计算出这个项目的最早完工时间。

#include<iostream>
#include<deque>
#include<queue>
#include<algorithm>
#include<string>
#include<cstring>
#include<cmath>
#include<iomanip>
#include<map>
#include<set>
#include<vector>
using namespace std; 
typedef long long ll;
const ll p=1e9+7,N=3e5+7;

int init[1005]={0};
int dis[1005];

struct node{
    int to,next,w;
}e[1005];

int head[1005];
int cnt=0;
int n,m;

void add(int u,int v,int w){
    e[cnt].to=v;
    e[cnt].w=w;
    e[cnt].next=head[u];
    head[u]=cnt++;
}
queue<int>q;
void check(){
	int num=0;
    while(!q.empty()){
        int x=q.front();q.pop();
        for(int i=head[x];~i;i=e[i].next){
        	
            int v=e[i].to;
            if(--init[v]==0) q.push(v);
            dis[v]=max(dis[v],dis[x]+e[i].w);
            num=max(num,dis[v]);
        }
    }
    for(int i=0;i<n;i++) if(init[i]){
		cout<<"Impossible";
		return;
	}
	cout<<num;
}
int main()
{
    memset(dis,-1,sizeof(dis));
    memset(head,-1,sizeof(head));
    cin>>n>>m;
    for(int i=0;i<m;i++){
        int x,y,w;
        cin>>x>>y>>w;
        add(x,y,w);
        init[y]++;
    }
	for(int i=0;i<n;i++) if(!init[i]){
		q.push(i);
		dis[i]=0;
	} 
	check();
    return 0;
}

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

本题要求:求出有向无环图中每一个节点的最早发生时间(示例图中每一个节点的最早发生时间以节点上方的黄色数字标出)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int dis[1005][1005];
int n,m;
void prim(){
    dis[0][0]=0;
    for(int k=0;k<n;k++)
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
                dis[i][j]=max(dis[i][j],dis[i][k]+dis[k][j]);              
}
int main()
{
    cin>>n>>m;
    memset(dis,-0x3f,sizeof(dis));
    for(int i=0;i<m;i++){
        int x,y,w;
        cin>>x>>y>>w;
        dis[x][y]=w;
    }
    prim();
    for(int i=0;i<n;i++) cout<<dis[0][i]<<endl;
    return 0;
}

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

本题要求:通过逆拓扑序,求出有向无环图中每一个节点的最迟发生时间

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int dis[1005][1005];
int n,m;
void prim(){
    dis[0][0]=0;
    for(int k=0;k<n;k++)
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
                dis[i][j]=max(dis[i][j],dis[i][k]+dis[k][j]);              
}
int main()
{
    cin>>n>>m;
    memset(dis,-0x3f,sizeof(dis));
    for(int i=0;i<n;i++) dis[i][i]=0;
    for(int i=0;i<m;i++){
        int x,y,w;
        cin>>x>>y>>w;
        dis[x][y]=w;
    }
    prim();
    int maxn=-1,pos=-1;
    for(int i=0;i<n;i++){
        if(maxn<dis[0][i]){
            maxn=dis[0][i];
            pos=i;
        }
    }
    for(int i=0;i<n;i++) cout<<maxn-dis[i][pos]<<endl;    //相当于倒序推.
    return 0;
}

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

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

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

求出有向无环图中的每一个关键路径及其发生时间

这三题是关联的,当最早发生时间==最迟发生时间,是关键路径。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int init[1005]={0};
int topo[1005]={0};
int n,m;
int a[1005][1005];
stack<int>q;
 
struct node1{
    int l,r,num;
}sg[1005];
bool cmp(node1 x,node1 y){
    if(x.num==y.num&&x.r!=y.r) return x.r<y.r;
    return x.num<y.num;
}
void toposort(){
    int t=0;
    for(int i=0;i<n;i++)
        if(!init[i]) q.push(i);
    while(!q.empty()){
        int u=q.top();q.pop();
        topo[t++]=u;
        for(int i=0;i<n;i++){
            if(a[u][i]!=0)
                if(--init[i]==0) q.push(i); 
        }
    }    
}
 
struct node{
    int to,next,w;
}e[1005];
int head[1005];
int cnt=0;
void add(int u,int v,int w){
    e[cnt].to=v;
    e[cnt].w=w;
    e[cnt].next=head[u];
    head[u]=cnt++;
}
 
int pos1[1005],pos2[1005];
 
void checkit(){
    memset(pos1,0,sizeof(pos1));
    for(int j=0;j<n;j++){
        int u=topo[j];
        for(int i=head[u];~i;i=e[i].next){
            int v=e[i].to;
            pos1[v]=max(pos1[v],pos1[u]+e[i].w);
        }
    }
    for(int i=0;i<n;i++) pos2[i]=pos1[topo[n-1]];
    for(int j=n-1;j>=0;j--){
        int u=topo[j];
        for(int i=head[u];~i;i=e[i].next){
            int v=e[i].to;
            pos2[u]=min(pos2[u],pos2[v]-e[i].w);
        }
    }
}
void redown(){
    cnt=0;
    memset(a,0,sizeof(a));
    memset(head,-1,sizeof(head));
}
int main()
{
    cin>>n>>m;
    redown();
    while(m--){
        int x,y,w;
        cin>>x>>y>>w;
        add(x,y,w);
        a[x][y]=w;
        init[y]++;
    }
     
    toposort();
    checkit();
    int t=0;
    for(int j=0;j<n;j++){
        for(int i=head[j];~i;i=e[i].next){
            int v=e[i].to;
            int sm=pos1[j];            //最早发生时间
            int bg=pos2[v]-e[i].w;    //最迟发生时间
            if(sm==bg) //printf("%d-->%d:%d\n",j,v,bg);
                sg[t].l=j,sg[t].r=v,sg[t++].num=bg;
        }
    }
    sort(sg,sg+t,cmp);        //答案要求的排序。
    for(int i=0;i<t;i++)
        printf("%d-->%d:%d\n",sg[i].l,sg[i].r,sg[i].num);
    //for(int i=0;i<n;i++) cout<<topo[i]<<endl;
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值