SDUT3117圖的基本存儲的基本方式一 二 三 四

Part 一 、 二、
鄰接矩陣 與鄰接表(鄰接鏈表)

圖的基本存儲的基本方式二

Time Limit: 1000 ms Memory Limit: 65536 KiB

Problem Description
解決圖論問題,首先就要思考用什麼樣的方式存儲圖。但是小鑫卻怎麼也弄不明白如何存圖纔能有利於解決問題。你能幫他解決這個問題麼?

Input
多組輸入,到文件結尾。
每一組第一行有兩個數n、m表示n個點,m條有向邊。接下來有m行,每行兩個數u、v代表u到v有一條有向邊。第m+2行有一個數q代表詢問次數,接下來q行每行有一個詢問,輸入兩個數爲a,b。

注意:點的編號爲0~n-1,2<=n<=500000 ,0<=m<=500000,0<=q<=500000,a!=b,輸入保證沒有自環和重邊

Output
對於每一條詢問,輸出一行。若a到b可以直接連通輸出Yes,否則輸出No。
Sample Input
2 1
0 1
2
0 1
1 0
Sample Output
Yes
No
Hint

Source
lin
以下該think總結轉載於xxx博主 鏈接, 用以學習 。
還有學姐 xxx 鏈接
THINK:圖的表示
(1)鄰接矩陣
用下標代表點的標號,以二維數組儲存數值表示邊的存在與否,或者邊的長度大小。
(2 )鄰接表
一、鄰接表
鄰接表是圖的一種鏈式存儲結構。
鄰接表中,對圖中每個頂點建立一個單鏈表,第i個單鏈表中的結點表示依附於頂點Vi的邊(對有向圖是以頂點Vi爲尾的弧)。
鄰接表的處理方法是這樣的:
(1)圖中頂點用一個一維數組存儲,當然,頂點也可以用單鏈表來存儲,不過,數組可以較容易的讀取頂點的信息,更加方便。
(2)圖中每個頂點vi的所有鄰接點構成一個線性表,由於鄰接點的個數不定,所以,用單鏈表存儲,無向圖稱爲頂點vi的邊表,有向圖則稱爲頂點vi作爲弧尾的出邊表。
這裏寫圖片描述
二、無向圖的鄰接表
這裏寫圖片描述
三、有向圖的鄰接表和逆鄰接表
(一)在有向圖的鄰接表中,第i個單鏈錶鏈接的邊都是頂點i發出的邊。
(二)爲了求第i個頂點的入度,需要遍歷整個鄰接表。因此可以建立逆鄰接表。
(三)在有向圖的逆鄰接表中,第i個單鏈錶鏈接的邊都是進入頂點i的邊。
這裏寫圖片描述
另外,十字鏈表:
對於有向圖來說,鄰接表是有缺陷的。入度和出度問題不能同時解決。十字鏈表,就是把鄰接表和逆鄰接表結合起來的,這樣既容易找到以v爲尾的弧,也容易找到以v爲頭的弧,因而比較容易求得頂點的出度和入度。

四、鄰接表小結
◆ 設圖中有n個頂點,e條邊,則用鄰接表表示無向圖時,需要n個頂點結點,2e個表結點;用鄰接表表示有向圖時,若不考慮逆鄰接表,只需n個頂點結點,e個邊結點。
◆ 在無向圖的鄰接表中,頂點vi的度恰爲第i個鏈表中的結點數。
◆ 在有向圖中,第i個鏈表中的結點個數只是頂點vi的出度。在逆鄰接表中的第i個鏈表中的結點個數爲vi的入度。
◆ 建立鄰接表的時間複雜度O(n+e)。
五、兩者使用途徑的區別:
如果圖中邊的數目遠遠小於n2稱作稀疏圖,這是用鄰接表表示比用鄰接矩陣表示節省空間;
如果圖中邊的數目接近於n2,對於無向圖接近於n*(n-1)稱作稠密圖,考慮到鄰接表中要附加鏈域,採用鄰接矩陣表示法爲宜。

在空間允許情況下:
在有向圖中求頂點的度採用鄰接矩陣比採用鄰接表表示更方便

鄰接表表示中第i個邊表上的結點個數就是頂點Vi的出度,求入度較困難,需遍歷個頂點的邊表
逆鄰接表表示中第i個邊表上的結點個數就是頂點Vi的入度,求出度較困難,需遍歷個頂點的邊表

在鄰接矩陣中求邊的數目必須檢測整個矩陣,所消耗的時間是O(n)
在鄰接表中求邊的個數,只要對每個邊表計數即可求得所消耗的時間是O(n+e)

附加:簡易的鄰接表儲存圖的oj 題。代碼

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct node //數據太大,不能用二維數組
{
    int data;
    struct node *next;
}node;
node *a[500000], *p;
int main()
{
    int n,m,i,u,v,q;
    while(~scanf("%d %d", &n, &m))
    {
        for(i=0; i < 500000; i++)
            a[i] = NULL; //初始化節點
        while(m--)
        {
            scanf("%d %d", &u, &v);
            if(a[u] == NULL)
            {
                p = (node *)malloc(sizeof(node)); //第一次連,直接連
                p->data = v;
                p->next = NULL;
                a[u] = p;
            }
            else
            {
                p = (node *)malloc(sizeof(node)); //已經連通,插入,
                p->data = v;
                p->next = a[u]->next;
                a[u]->next = p;
            }
        }
        scanf("%d",&q);
        while(q--)
       {
        int flag = 0;
        scanf("%d %d", &u, &v);
        p = a[u];
        while(p != NULL)
        {
            if(p->data == v)
            {
                flag = 1;
                break;
            }
            p = p->next;
        }
        if(flag == 1)
            printf("Yes\n");
            else
                printf("No\n");
       }
    }
        return 0;
}


/***************************************************
User name: i am your lover
Result: Accepted
Take time: 56ms
Take Memory: 5988KB
Submit time: 2018-08-
****************************************************/

圖的基本存儲的基本方式一
Time Limit: 1800 ms Memory Limit: 65536 KiB
Input
多組輸入,到文件結尾。

每一組第一行有兩個數n、m表示n個點,m條有向邊。接下來有m行,每行兩個數u、v代表u到v有一條有向邊。第m+2行有一個數q代表詢問次數,接下來q行每行有一個詢問,輸入兩個數爲a,b。

注意:點的編號爲0~n-1,2<=n<=5000 ,n*(n-1)/2<=m<=n*(n-1),0<=q<=1000000,a!=b,輸入保證沒有自環和重邊

Output
對於每一條詢問,輸出一行。若a到b可以直接連通輸出Yes,否則輸出No。

Sample Input
2 1
0 1
2
0 1
1 0
Sample Output
Yes
No
Hint
Source
lin
臨街矩陣

#include <stdio.h>
#include <string.h>

bool map[5000][5000];//標記路徑,bool類型在存儲二值變量,
//或者說只有真假時,更具優勢,
//因爲只有0和1即false和true,省空間
int main()
{
    int n, m, u, v;
    while(~scanf("%d%d",&n,&m))
    {
        memset(map, 0, sizeof(map));
        for(int i = 0; i < m; i++)
        {
            scanf("%d%d",&u,&v);
            map[u][v] = 1;
        }
        int q;
        scanf("%d",&q);
        while(q--)
        {
            int a, b;
            scanf("%d%d",&a,&b);
            if(map[a][b])
               {
                printf("Yes\n");
               }
           else  printf("No\n");
        }
    }
    return 0;
}

part 3. 三 結構體+數組(邊集數組)

圖的基本存儲的基本方式三

Time Limit: 1000 ms Memory Limit: 65536 KiB

Problem Description
解決圖論問題,首先就要思考用什麼樣的方式存儲圖。但是小鑫卻怎麼也弄不明白如何存圖纔能有利於解決問題。你能幫他解決這個問題麼?

Input
多組輸入,到文件結尾。
每一組第一行有兩個數n、m表示n個點,m條有向邊。接下來有m行,每行兩個數u、v、w代表u到v有一條有向邊權值爲w。第m+2行有一個數q代表詢問次數,接下來q行每行有一個詢問,輸入一個數爲a

注意:點的編號爲0~n-1,2<=n<=500000 ,0<=m<=500000,0<=q<=500000,u!=v,w爲int型數據。輸入保證沒有自環和重邊

Output
對於每一條詢問,輸出一行兩個數x,y。表示排序後第a條邊是由x到y的。對於每條邊來說排序規則如下:
權值小的在前。

權值相等的邊出發點編號小的在前

權值和出發點相等的到達點編號小的在前
注:邊的編號自0開始

Sample Input
4 3
0 1 1
1 2 2
1 3 0
3
0
1
2
Sample Output
1 3
0 1
1 2
Hint

Source
lin
瞭解下qsort函數
C/C++中有一個快速排序的標準庫函數 qsort ,在stdlib.h 中聲明,其原型爲:
void qsort(void base, int nelem, unsigned int width, int ( pfCompare)( const void , const void ));

  使用該函數,可以對任何類型的一維數組排序。該函數參數中,base 是待排序數組的起始地址,nelem 是待排序數組的元素個數,width 是待排序數組的每個元素的大小(以字節爲單位),最後一個參數 pfCompare 是一個函數指針,它指向一個“比較函數”。排序就是一個不斷比較並交換位置的過程。qsort 如何在連元素的類型是什麼都不知道的情況下,比較兩個元素並判斷哪個應該在前呢?答案是,qsort 函數在執行期間,會通過pfCompare指針調用一個 “比較函數”,用以判斷兩個元素哪個更應該排在前面。這個“比較函數”不是C/C++的庫函數,而是由使用qsort 的程序員編寫的。在調用qsort 時, 將“比較函數”的名字作爲實參傳遞給pfCompare。程序員當然清楚該按什麼規則決定哪個元素應該在前,哪個元素應該在後,這個規則就體現在“比較函數”中。

qsort 函數的用法規定,“比較函數”的原型應是:int 函數名(const void * elem1, const void * elem2);該函數的兩個參數,elem1 和elem2,指向待比較的兩個元素。也就是說, * elem1 和* elem2 就是待比較的兩個元素。該函數必須具有以下行爲:

  1) 如果 * elem1 應該排在 * elem2 前面,則函數返回值是負整數(任何負整數都行)。

  2) 如果 * elem1 和* elem2 哪個排在前面都行,那麼函數返回0

  3) 如果 * elem1 應該排在 * elem2 後面,則函數返回值是正整數(任何正整數都行)。

以下代碼原作者忘了誰了 哈哈哈
以下爲AC 代碼 當做學習整理

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define Max 591000
struct node
{
    int u;//記錄端點
    int v;//記錄端點
    int w;//記錄權值
}s[500010];
int cmp(const void *a, const void *b)
{
    struct node *c = (struct node *)a;
    struct node *d = (struct node *)b;
    if(c->w != d->w) return c->w - d->w;
    else if (c->u != d->u)
        return c->u - d->u;
    else
        return c->v - d->v;
}
int main()
{
    int i,n,m,t,q;
    while(~scanf("%d %d",&n,&m))
    {
        memset(s,Max, sizeof(struct node)); //對數組初始化防止影響結果
        for(i = 0; i < m; i++)
        {
            scanf("%d %d %d",&s[i].u, &s[i].v, &s[i].w);
        }
        qsort(s,m,sizeof(s[0]),cmp);
        scanf("%d",&q);
        while(q--)
        {
            scanf("%d",&t);
            printf("%d %d\n",s[t].u, s[t].v);
        }
    }
    return 0;
}
發佈了43 篇原創文章 · 獲贊 35 · 訪問量 8287
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章