1. 程式人生 > >圖論小知識

圖論小知識

/*******************************************
   鄰接表 儲存圖
   空間複雜度O(m+n)
   時間複雜度O(m)
   優點:
   缺點:
********************************************/
#include<stdio.h>
#define MAXN 1111
#define MAXM 1111
int head[MAXN];//儲存起點為Ui的位置
struct node
{
	int from;//起點
	int to; //終點
	int cap;//權值
	int next;//
}edge[MAXM];
int tot=0;
void add(int u, int v, int cap ,int rw =0 )//建邊
{
    node E = {u, v, cap, head[u]};  
    edge[ tot ] = E;  
    head[ u ] = tot++;  

    node E2 = {v, u, rw,  head[v]};  //反向邊
    edge[ tot ] = E2;  
    head[ v ] = tot++;  
}  
int main()
{
	for(i=1;i<=n;i++)
	{
		for(k=head[i];k!=-1;k=edge[k].next)
		{
				printf("%d %d %d\n",edge[j].from,edge[j].to,edge[j].cap);
		}
	}
}

歐拉回路:從一個點恰通過每條邊一次 最終回到起點

條件:1.所有點都是連通的

            2.(對於無向圖)度數為奇數的點的個數為0 (對於有向圖)每個點的入度==出度

變形尤拉圖:可以不回到起點,經過所有邊

條件:1.所有點都是連通的 

     2.(對於無向圖)度數為奇數的點的個數為2(起點和終點)

       (對於有向圖)存在1個點的入度+1==出度(起點)

   存在1個點的出度+1==入度(終點)

最小環證明:(可用floyd求)

一個環中的最大結點為k(編號最大),與他相連的兩個點為i,j,這個環的最短長度為g[i][k]+g[k][j]+i到j的路徑中,所有結點編號都小於k的最短路徑長度
根據floyd的原理,在最外層迴圈做了k-1次之後,dist[i][j]則代表了i到j的路徑中,所有結點編號都小於k的最短路徑
綜上所述,該演算法一定能找到圖中最小環


void dfs(int i, int j) {
    int k = f[i][j];
    if(k == 0)  {
        pash[num++] = j;
        return ;
    }
    dfs(i, k);
    dfs(k, j);
}   


//---------------------------------------------------
     for(k = 1; k <= n; ++k) {
        for(i = 1; i < k; ++i) {
            for(j = i + 1; j < k; ++j) {
                if(ans > dis[i][j] + mp[i][k] + mp[k][j]) {    //找最小環
                    ans = dis[i][j] + mp[i][k] + mp[k][j];
                    num = 0;
                    pash[num++] = i;
                    dfs(i, j);
                    pash[num++] = k;
                }
            }
        }

        for(i = 1; i <= n; ++i) {
            for(j = 1; j <= n; ++j) {
                if(dis[i][j] > dis[i][k] + dis[k][j]) {
                    dis[i][j] = dis[i][k] + dis[k][j];
                    f[i][j] = k;    //f[i][j]記錄i到j經過的點
                }
            }
        }
    }

最小邊覆蓋 = 最大獨立集 = |V| - 最大匹配數
這個是在原圖是二分圖上進行的
最小路徑覆蓋和最小邊覆蓋不同,不要求給的圖是二分圖,而是要求是N x N的有向圖,不能有環,然後根據原圖構造二分圖,構造方法是將點一分為二,如,i分為i1和i2然後如果i和j有邊,那麼就在i1和j2之間連一條邊。由此構成二分圖
然後最小路徑覆蓋 = n-m,n為原圖的點的個數,m為新造二分圖的最大匹配。證明也是特別簡單的,根據定義最小路徑覆蓋裡要求同一個點只可以屬於一條路徑,即路徑時不可以開叉的,如果在二分圖裡選兩條有公共點的邊那麼反應在原圖上就是路徑有岔路了,所以二分圖裡選的邊必須是無公共交點的,這就是轉化到最大匹配了。
總結:
【無向圖的最大獨立數】: 從V個頂點中選出k個頂,使得這k個頂互不相鄰。 那麼最大的k就是這個圖的最大獨立數。
【無向圖的最大團】:  從V個頂點選出k個頂,使得這k個頂構成一個完全圖,即該子圖任意兩個頂都有直接的邊。
【最小路徑覆蓋(原圖不一定是二分圖,但必須是有向圖,拆點構造二分圖)】:在圖中找一些路徑,使之覆蓋了圖中的所有頂點,且任何一個頂點有且只有一條路徑與之關聯。最小路徑覆蓋 = |V| - 最大匹配數
【最小邊覆蓋(原圖是二分圖)】:在圖中找一些邊,使之覆蓋了圖中所有頂點,且任何一個頂點有且只有一條邊與之關聯。最小邊覆蓋 = 最大獨立集 = |V| - 最大匹配數
【最小頂點覆蓋】:用最少的點(左右兩邊集合的點)讓每條邊都至少和其中一個點關聯。

PS: 原來學二分匹配時就整理過這些數字,他們之間關係是很多。如: 最小覆蓋數+最大獨立數 = 頂點數。 雖然求出他們都是np問題。但對於特殊的圖還是有好的演算法的,如:

在二分圖中,最小覆蓋數 等於 最大匹配數,而最大獨立數又等於頂點數減去最小覆蓋數(=最大匹配數),所以可以利用匈牙利求出最大獨立數等等。

a.點覆蓋集:無向圖G的一個點集,使得該圖中所有邊都至少有一點端點在該集合內。

b.點獨立集:無向圖G的一個點集,使得任兩個在該集合中的點在原圖中不相鄰。

c.最小點覆蓋集:無向圖G中點數最少的點覆蓋集

d.最大點獨立集:無向圖G中,點數最多的點獨立集

e.最小點權覆蓋集:帶點權的無向圖中,點權之和最小的點覆蓋集

f.最大點權獨立集:實在帶點權無向圖中,點權之和最大的點獨立集

性質:

最大團 = 補圖的最大獨立集

最小邊覆蓋 = 二分圖最大獨立集 = |V| - 最小路徑覆蓋

最小路徑覆蓋 = |V| - 最大匹配數

最小頂點覆蓋 = 最大匹配數

最小頂點覆蓋 + 最大獨立數 = |V|

最小割 = 最小點權覆蓋集 = 點權和 - 最大點權獨立集

S-SAT建圖:

  2-SAT問題遠沒有網路流那樣複雜,只要抓住關係建好圖基本就直接可以解了,在這類問題中建邊的規則就是“必須”,對於邊<i,j>,它的意義就是選擇了i就必須選j。

  對於題目中給出的每對關係都可以化成下面的幾種形式:

   A,B不能同時取  <A,B'><B,A'>

   A,B不能都不取  <A',B><B',A>

   A,B必須都取或者都不取  <A,B><B,A><A',B'><B',A'>

   必須取A  <A',A>

  主要的模型就這四個,其餘的都可以通過徳摩根律化成上面的形式,前三個的建圖都不難理解,對於第四個,這樣建邊是因為如果選了A'就必須選A,顯然是不符合邏輯的,也就是說A'不可選,那麼自然要選擇A了。

割點、割橋

割點-定理:無向圖中,非根結點u是割點,當且僅當u存在一個子節點v ,使得v及其後代都沒有反向邊連回u的祖先(不含u)

根節點u割點,是當且僅當子節點數大於2

割邊集(網路流)

在跑一次最大流之後,以s點開始 bfs一次殘留網路,能走到的點為S集

邊的兩端分別在S ,T集 中則為割邊