三种存图方法

邻接矩阵

容易存储,修改,处理重边和查询。但是对于稀疏图来说非常非常浪费空间

挖地雷

dp:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int t,ans;
int a[205],g[205][205],pre[205],f[205];
void print(int x){
    if (pre[x]==0){
        printf("%d",x);
        return;
    }
    print(pre[x]);
    printf(" %d",x); 
}
int main(){
    int n;
    scanf("%d",&n);
    for (int i=1;i<=n;i++)scanf("%d",&a[i]);
    int x;
    for(int i=1;i<n;i++){
        for(int j=i+1;j<=n;j++){
            scanf("%d",&x);
            if(x)g[i][j]=1;//注意题干是单向边i->j
        }//邻接表存图
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){//遍历父节点 
            if(g[j][i]&&f[j]>f[i]){
                f[i]=f[j];//dp,f[i]为以第i个节点结束的最大值
                pre[i]=j;
            }
        }
        f[i]+=a[i];//父节点+=子节点 
        if (f[i]>ans) {
            ans=f[i];
            t=i;
        }
    }
    print(t);
    printf("\n%d",ans);
    return 0;
}

邻接表

当点数大于1000的时候,我们无法使用二维数组进行存储,故考虑不定长数组vector,但有时我们需要将到达的点和权值一起存入,故需要结构体。

查找文献

set存子节点:

//选一个好的数据结构很重要 
//只有c++11能通过编译 
#include<bits/stdc++.h>
using namespace std;
int n,m;
set<int> e[100009];//默认从小到大 
bool vis[100009];
void init(){
    int u=0,v=0;
    for(scanf("%d%d",&n,&m);m;--m){     
        scanf("%d%d",&u,&v);
        e[u].insert(v);
    }
}
void dfs(int x=1){
    if(vis[x])return;
    vis[x]=1;
    printf("%d ",x);
    for(int v:e[x])dfs(v);
}
void bfs(){
    queue<int>q;
    q.push(1);
    while(!q.empty()){
        int x=q.front();q.pop();
        if(vis[x])continue;vis[x]=1;
        printf("%d ",x);
        for(int v:e[x])q.push(v);
    }
}
int main(){
    init();
    dfs();
    putchar('\n');
    memset(vis,0,sizeof(vis));
    bfs();
    putchar('\n');
    return 0;
}
/*
for(int x:nums)即 
for(int i=0;i<=nums.length;i++)
*/

前向星

优点:

a.内存利用率高:相比vector实现的邻接表而言,可以准确开辟最多边数的内存,不像vector实现的邻接表有爆内存的风险
b.对不确定的边操作比较方便,和邻接表一样不会遍历到不存在的边

缺点:

a.操作复杂一点:要求比较熟练,不熟练写起来比较慢
b.重边不好处理:这点与邻接表一样,只有通过遍历判重
c.对确定边操作效率不高:也与邻接表一样,不能通过两点马上确定边,只能遍历查找

最大食物链计数

拓扑排序:

#include<bits/stdc++.h>
#define maxn 5010
#define maxe 500010
using namespace std;
const int mod=80112002;
int n,m,h[maxn],in[maxn],out[maxn],f[maxn],ans;
struct AB{
   int a,b,n;
}d[maxe];
queue<int> q;
int main(){
    cin>>n>>m;
    for(int i=1,a,b;i<=m;i++){
       scanf("%d%d", &a, &b);
       d[i].a=a, d[i].b=b;
       d[i].n=h[a], h[a]=i;//注意 
       out[a]++, in[b]++;
    }
    for(int i=1;i<=n;i++){
       if(in[i]==0){
           f[i]=1;//注意
           q.push(i);
       }
    }
    while(!q.empty()){
       int a=q.front(); q.pop();
       for(int k=h[a]; k ;k=d[k].n){
           int b=d[k].b;
           f[b]+=f[a];
           f[b]%=mod;
           in[b]--;
           if(in[b]==0){
               if(out[b]==0){
                   ans+=f[b];
                   ans%=mod;
               }//出度为0的点为食物链终点,记录答案,并且不必入队
               else q.push(b);//没有出度,那么进队了也没有意义 
           }
       }
    }
    cout<<ans; 
}

推荐好文:存图的三种方式

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值