图论基础知识.

  今天先写一些基础的图论知识;

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;
}

 

posted @ 2019-01-01 12:58  Tyouchie  阅读(334)  评论(0编辑  收藏  举报