图论基础知识.
今天先写一些基础的图论知识;
1.floyed算法;
2.spfa算法;
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,最后输出就好这样操作比较简单;
存图用邻接矩阵就好了
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知道每只奶牛都在各自喜欢的牧场(一个牧场不一定只有一头牛)。给出各头牛在的牧场和牧场间的路线,找出使所有牛到达的路程和最短的牧场(他将把糖放在那)
农夫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),当然,连接是双向的
第二行到第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; }