问题 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;
}