几种图的构建方法的总结


      图的构成有各种各样的方式,只要你认为逻辑上能形成一张图,并且你看得懂自己的构图数据,那么就是一张好图。。(这只是我的一点认为)


为了打ACM不得不使用简洁,效率高的代码(说白了就是赶时间)  下面总结几种方法


第一种    也是目前比较流行的   邻接表形式

/**********************************************************************************************
邻接表法:每个节点i都有一个链表,里面保存着从i出发的所有边

Edge是边的信息 
        首先:e[i] 代表了 第i条边
            1 . to是它指向的那个点
            2 . w代表这条边的权值
            3 . next代表与这个点相连的下一条边的序号(这里的“下一条”边其实是先输入的边呵呵)
head
            head[i]记录的是第i个节点发出的边的序号
            
************************************************************************************************/
struct  Edge{  
    int to;  
    int w;  
    int next;  
}e[MAX];  
int head[MAX];
//初始化 因为各个节点没有发出边,所以head数组置为 -1   
memset(head,-1,sizeof(head));  
//输入过程(建图过程)  
scanf("%d %d %d", &from, &to, &w1);  
e[i].to = to; 
e[i].w = w1; 
e[i].next = head[from]; 
head[from] = i;  
i++;  
//遍历某个节点发出的所有边  now表示现在的节点
for(i = head[now]; i != -1; i = edge[i].next)  
{  
    int adj = edge[i].to;  
    int w = edge[i].w;  
    //do something...  
}  


第二种      尽管第一种邻接表很流行,但在概念上却没有第二种 —— 用vector数组更加简单

struct Edge{
    int from, to, w;
    Edge(int u, int v, int d):from(u), to(v), w(d){}
};
vector<Edge> edges;
vector<int> G[MAX];

scanf("%d %d %d", &u, &v, &w1);
edges.push_back(Edge(u, v, w1));
edges.push_back(Edge(v, u, w1));  //如果是无向图,还应该反向添加一次
int c = edge.size();  //c可以代表总的边的条数,而条数等于边的序号,即第i条边的序号为i
G[u].push_back(c - 2);
G[v].push_back(c - 1);

//若想遍历与某点x相关联的边
for(int i = 0; i < G[x].size(); i++){
    //do something...
}

第三种:而vector里存的东西也不一定要是直接储存边Edge   也可以是与这个点相连的边的编号(该点作为边前端。。)


下面上代码


struct Edge{
    int u, v;
    Edge(int u = 0, int v = 0):u(u),v(v){};  
}e[MAX];
vector<int> G[MAX];
//G[i]储存的是与第i个点相连的所有边的序号
//构图过程
int cnt = 0;
scanf("%d %d", &u, &v);
e[++cnt].Edge(u, v);
<pre name="code" class="cpp">G[u].push_back(cnt);
e[++cnt].Edge(v, u);//如果是无向或需要构建反向图G[v].push_back(cnt);
//遍历过程
for(int i = 0; i < G[x].size(); i++){ int tmp = e[G[x][i]].v;//取出与x相连的点的序号,然后可以对点进行一系列操作 //do somethings...}
 

第四种:以上都是保存边的信息,然而用vector来保存点的信息也是不错的


struct Node
{
    int to;  //与这个点相连的点
    int val; //以这个点射出的边的权值之类
    int rev; //这个点的反向边
};
vector<Node> v[MAX];
//添加各个点
void add_node(int from, int to, int cap)
{
    v[from].push_back((Node){to, cap, v[to].size()});
    v[to].push_back((Node){from, 0, v[from].size() - 1});//这种方式储存反向边,是为了便于查找
    //也就是说如果要取用与u发出的那条边的反向边,只要v[u.to][u.rev]...
}
//如要改变点中的信息去取某个点的时候可以用引用的方式 例 Node &tmp = v[u][i]....
int main()
{
    //.....
}


其他的矩阵就不再写了把,,一个二维数组就ok   就是空间复杂度实在是太高   而vector的时间效率也不是太好(但一般题目不会卡这一点时间)




  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值