fjutacm 1911 建图基础(一) 链式前向星、动态数组去重

Problem Description
给你一副N个点M条边的有向图(点的编号是从1~N),然后有Q次询问,每次询问输入一个点的编号,按升序输出与这个点连接的所有点,对于每次询问,每个关联点只输出一次,如果没有关联点,则输出NULL。

Input
有多组测试案例.
第一行,输入三个正整数N,M,Q,分别表示N个点,M条边,Q次询问(0<N<=10000,0<M<=1000000,0<Q<=100)。

接下来有M行,每一行输入两个正整数a,b。表示有编号点a指向编号点b。

接下来有Q行,每一行输入一个正整数c,表示询问这个点。

全部数据以及答案的范围均在int里面。

Output
对于每一组测试案例,按照题目要求,输出答案

SampleInput
3 2 2
1 2
2 3
1
3
3 4 1
1 3
1 1
1 2
1 3
1
SampleOutput
2
NULL
1
2
3

中文题面,就不读题了。这篇博客主要用链式前向星和vector去重解题,也许也有别的解法,就不谈了,想讲的都在注释里,直接上代码。

#include<vector>
#include<algorithm>
#include<stdio.h>
using namespace std;
const int MAXP=10005;
const int MAXL=1000005;

int first[MAXP];  /// 存放每个点相关的Edge在edge中的位置,大小为点的个数
int flag;   /// 把所有边一个一个往edge[]里塞的时候要用

struct Edge
{
  int to;      /// 该边的终点,起点在first里
  int next;    /// edge[i].next表示第i条边的上一条边在edge数组中的位置
}edge[MAXL];   /// 记录边,大小为边的个数

void init(int n)
{
  flag = 0;
  for (int i=1; i<=n; i++)
    first[i] = -1;
}

void create(int a, int b)
{
  edge[flag].to = b;          /// 在edge[]的flag处记录这条以a为起点的边的终点b
  edge[flag].next = first[a]; /// 这条边的next指向上一个以a为起点的边在edge[]中
                              ///的位置,这样形成一个链表的结构。也就是说,访问
                              ///完某一条边edge[i],我可以根据edge[i].next知道还
                              ///有没有a为起点的边,有的话它在edge[]的哪里,方便
                              ///我们直接去访问;next为-1时就是没边了
  first[a] = flag++;          /// 把指针flag往后推一位
}

int main()
{
  int n, m, q, a, b, i;
  vector<int>gather;    ///之后应题意,排序、去重要用
  while (~scanf("%d%d%d", &n, &m, &q))
  {
    init(n);
    while (m--)
    {
      scanf("%d%d", &a, &b);
      create(a, b);
    }
    while (q--)
    {
      scanf("%d", &a);
      if (first[a] == -1)
        puts("NULL");
      else
      {
        gather.clear();
        for (i=first[a]; i!=-1; i=edge[i].next)/// first[]记录的是以i为起点的最后
    ///一条边在edge[]中的位置,结合上面的注释,为什么这么遍历应该就很好理解了
          gather.push_back(edge[i].to);///一条一条统统压进gather
        
        sort(gather.begin(), gather.end());/// 划重点,vector的参数要传迭代器,而
          ///.begin()和.end()返回的正是指向头和尾的迭代器(我理解成vector的地址)
        
        gather.erase(unique(gather.begin(), gather.end()), gather.end());/// 前面的
        ///unique()把出现过的元素只把一个推到前面,多余的都在后面,返回的是无重
        ///复序列尾部再往后一位的迭代器,.erase()擦去制定位置或制定区间元素(记
        ///得这个时候.size()是会相应减少的,所以外面如果有整型常量,譬如n在记录
        ///数组长度,记得减去被擦去区间的长度,否则小心遍历时出错),这一套操
        ///作实现vector动态数组的去重
        for (i=0; i<(int)gather.size(); i++)
          printf("%d\n", gather[i]); /// 遍历一遍,输出题目要求的答案
      }
    }
  }
  return 0;
}

发布了19 篇原创文章 · 获赞 0 · 访问量 510

猜你喜欢

转载自blog.csdn.net/qq_43317133/article/details/98206659