1. 程式人生 > >圖論基礎知識.

圖論基礎知識.

最短 dig alt next spfa 了吧 geode 尋找 .com

今天先寫一些基礎的圖論知識;

1.floyed算法;

2.spfa算法; 3.dijkstra(迪傑斯特拉)算法;(先不寫)

1.floyed算法

可以找到任意兩點之間的最短路,即dis[i][j];

原理:圖的傳遞閉包思想;時間復雜度:O(n*n*n);
思想也比較好理解(三角形任意兩邊之和大於第三邊嘛,如果出現不符合,就更新距離,這樣比較好想)


例題oj1212
圖G是一個無向連通圖,沒有自環,並且兩點之間至多只有一條邊。我們定義頂點v,u最短路徑就是從v到u經過邊最少的路徑。所有包含在v-u的最短路徑上的頂點被稱為v-u的Geodetic頂點,這些頂點的集合記作I(v, u)。
我們稱集合I(v, u)為一個Geodetic集合。
例如下圖中,I(2, 5)={2, 3, 4, 5},I(1, 5)={1, 3, 5},I(2, 4)={2, 4}。
技術分享圖片


技術分享圖片

給定一個圖G和若幹點對v,u,請你分別求出I(v, u)。
輸入:
第一行兩個整數n,m,分別表示圖G的頂點數和邊數(頂點編號1-n)
  下接m行,每行兩個整數a,b表示頂點a和b之間有一條無向邊。
  第m+2行有一個整數k,表示給定的點對數。
  下接k行,每行兩個整數v,u。
輸出:
共k行,每行對應輸入文件中每一個點對v,u,按頂點編號升序輸出I(v, u)。同一行的每個數之間用空格分隔。

思想:就是跑一個floyed,記錄所經過的每一個點再輸出就好了吧
原來看書 好像可以做一個p[i][j]數組用來儲存所經過的點..
但是我做這個題的時候還不會,所以先跑了一個floyed,最後尋找如果i到k再到j的距離等於i到j的最短路,那不是很明顯他在最短路上嘛,記錄一個每一個k,最後輸出就好這樣操作比較簡單;
存圖用鄰接矩陣就好了
#include<bits/stdc++.h>
using
namespace std; int dis[1500][1500],a[1500],n,m,t,f[1500][1500],xx,yy; inline int read() { int x=0,f=1; char ch=getchar(); while(!isdigit(ch)){if(ch==-) f=-1;ch=getchar();} while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*f; } inline void dfs() { for(int k=1
;k<=n;k++) for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) { if(dis[i][k]+dis[k][j]<=dis[i][j]) { dis[i][j]=dis[i][k]+dis[k][j]; } } } int main() { memset(dis,10,sizeof(dis)); m=read();n=read(); for(int i=1;i<=n;i++) { cin>>xx>>yy; dis[xx][yy]=1; dis[yy][xx]=1; } // cout<<dis[4][5]<<endl; dfs(); t=read(); int x,y; for(int i=1;i<=t;i++) { x=read();y=read(); int s=0; a[++s]=x; for(int j=1;j<=n;j++) { if(dis[x][j]+dis[j][y]==dis[x][y]) a[++s]=j; } //cout<<dis[2][4]<<‘ ‘<<dis[4][5]<<endl; a[++s]=y; sort(a+1,a+s+1); for(int j=1;j<=s;j++) { cout<<a[j]<< ; } cout<<endl; } return 0; }


2.spfa算法
關於spfa,當初聽課的時候學長講:關於spfa,它死了.. 用棧來模擬,每次取出對頭,判斷是否需要更新,用dis數組存到任意一點的最短距離; oj1215 農夫John發現做出全威斯康辛州最甜的黃油的方法:糖。把糖放在一片牧場上,他知道N(1<=N<=500)只奶牛會過來舔它,這樣就能做出能賣好價錢的超甜黃油。當然,他將付出額外的費用在奶牛上。
農夫John很狡猾。像以前的Pavlov,他知道他可以訓練這些奶牛,讓它們在聽到鈴聲時去一個特定的牧場。他打算將糖放在那裏然後下午發出鈴聲,以至他可以在晚上擠奶。
農夫John知道每只奶牛都在各自喜歡的牧場(一個牧場不一定只有一頭牛)。給出各頭牛在的牧場和牧場間的路線,找出使所有牛到達的路程和最短的牧場(他將把糖放在那) 輸入: 第一行: 三個數:奶牛數N,牧場數(2<=P<=800),牧場間道路數C(1<=C<=1450)
第二行到第N+1行: 1到N頭奶牛所在的牧場號
第N+2行到第N+C+1行: 每行有三個數:相連的牧場A、B,兩牧場間距離(1<=D<=255),當然,連接是雙向的 輸出:一行 輸出奶牛必須行走的最小的距離和
#include<bits/stdc++.h>
using namespace std;
#define N 1500
int lin[N],tot;
int n,m,h,w[N],vis[N],dis[N],d[N];
int xx,yy,zz;
long long minn=100100000000000ll,ans=0;
struct gg
{
    int x,y,v;
    int next;
}a[N<<1];
inline void init(int xx,int yy,int vv)
{
    a[++tot].y=yy;
    a[tot].next=lin[xx];
    a[tot].v=vv;
    lin[xx]=tot;
}
inline void spfa(int s)
{
    memset(vis,0,sizeof(vis));
    memset(dis,257,sizeof(dis));
    queue<int> q;
    dis[s]=0;vis[s]=1;q.push(s);
    while(q.size())
    {
        int x=q.front();q.pop();
        for(int i=lin[x];i;i=a[i].next)
        {
            int v=a[i].y;
            if(dis[v]>dis[x]+a[i].v)
            {
                dis[v]=dis[x]+a[i].v;
                if(!vis[v])    vis[v]=1,q.push(v);
            }
        }
        vis[x]=0;
    }
}
int main()
{
    cin>>n>>m>>h;
    for(int i=1;i<=n;i++)
        cin>>d[i];
    for(int i=1;i<=h;i++)
    {
        cin>>xx>>yy>>zz;
        init(xx,yy,zz);
        init(yy,xx,zz);
    }
    for(int i=1;i<=m;i++)
    {
        spfa(i);ans=0;
        for(int  j=1;j<=n;j++)
            ans+=dis[d[j]];
        if(ans<minn) minn=ans;
    }
    cout<<minn;
    return 0;
}

圖論基礎知識.