从今天开始就学图论啦
folyd和dijsktra这两个算法虽然以前学过 但都理解的不透彻(其实就是只记得名字和大概罢了。。)
多的不说上模板吧
1.floyd
//时间复杂度O(n^3) 空间复杂度O(n^2) 多源最短路
/*
4 8
1 2 2
1 3 6
1 4 4
2 3 3
3 1 7
3 4 1
4 1 5
4 3 12
*/
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 1000
#define inf 0x7ffffff
using namespace std;
int e[N][N];
int main(){
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)//初始化
for(int j=1;j<=n;j++)
if(i==j) e[i][j]=0;
else e[i][j]=inf;
int x,y,z;
for(int i=1;i<=m;i++){
scanf("%d%d%d",&x,&y,&z);
e[x][y]=z;
}
for(int k=1;k<=n;k++)//关于k在最外层的问题:其实是f[k][i][j] 由f[k-1][i][j]和f[k-1][i][k]+f[k-1][k][j]转移而来 类似背包 可以省略k这一维
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(e[i][j]-e[i][k]>e[k][j])//为了防止d[i][k]+d[k][j]时两个inf相加超过int范围成了负数 所以改一下
e[i][j]=e[i][k]+e[k][j];
for(int i=1;i<=n;i++) {
for(int j=1;j<=n;j++)
printf("%d ",e[i][j]);
printf("\n");
}
return 0;
}
2.dijsktra
/*
单源点最短路 用优先队列降低了时间复杂度
4 8
1 2 2
1 3 6
1 4 4
2 3 3
3 1 7
3 4 1
4 1 5
4 3 12
*/
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define inf 0x7fffff
using namespace std;
struct node{
int dd;
int vv;
node(int x,int y){
dd=x;vv=y;
}
bool operator <(node xx)const{//按距离构建从小到大优先队列
return dd>xx.dd;
}
};
priority_queue <node>q;
int cnt,n,m;
int head[1000];
struct data{int to,next,w;}e[2000];
int flag[1000],d[1000];
void insert(int x,int y,int z){
e[++cnt].to=y;e[cnt].w=z;e[cnt].next=head[x];head[x]=cnt;
}
int main(){
scanf("%d%d",&n,&m);
int x,y,z;
for(int i=1;i<=m;i++) {
scanf("%d%d%d",&x,&y,&z);
insert(x,y,z);
}
int s=1;//起点编号
for(int i=1;i<=n;i++)
d[i]=inf;
d[s]=0;
q.push(node(0,s));//起点先入队
for(int i=1;i<=n;i++)
{
int k=q.top().vv;//找出最小的距离
flag[k]=1;//标记k 此时k已经是最短路
q.pop();
for(int i=head[k];i;i=e[i].next)//从最小距离的点进行松弛
{
int kk=e[i].to;
if(!flag[kk]&&d[kk]>d[k]+e[i].w)//如果k可以作为中转点就更新
{ d[kk]=d[k]+e[i].w;q.push(node(d[kk],kk));}
}
}
for(int i=1;i<=n;i++)
printf("%d ",d[i]);
return 0;
}
3.bellman-ford
//解决有负权回路的问题
//时间复杂度O(NE) N个顶点E条边
/*
3 3
1 2 2
2 3 2
3 1 -5
*/
/*
4 8
1 2 2
1 3 6
1 4 4
2 3 3
3 1 7
3 4 1
4 1 5
4 3 12
*/
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define inf
using namespace std;
struct node{
int x,y,w;
}e[100005];
int cnt;bool flag;
int d[10005];
int main(){
int n,m;
scanf("%d%d",&n,&m);
int x,y,z;
for(int i=1;i<=m;i++){
scanf("%d%d%d",&x,&y,&z);
e[++cnt].x=x;e[cnt].y=y;e[cnt].w=z;
}
int s=1;//起点
memset(d,127,sizeof(d));
d[s]=0;
for(int i=1;i<=n-1;i++)//一个点最多由n-1个点更改
for(int j=1;j<=m;j++)
if(d[e[j].y]>d[e[j].x]+e[j].w)
d[e[j].y]=d[e[j].x]+e[j].w;
for(int i=1;i<=m;i++)//判断负权回路
if(d[e[i].y]>d[e[i].x]+e[i].w)//如果还能改说明有负权回路
flag=1;
for(int i=1;i<=n;i++)
printf("%d ",d[i]);
cout<<endl;
if(flag==1) printf("有负权回路");
else printf("没有负权回路");
return 0;
}
4.spfa
//spfa 在bellman-ford上改进
//时间复杂度O(k*E) k<=2
/*
3 3
1 2 2
2 3 2
3 1 -5
*/
/*
4 8
1 2 2
1 3 6
1 4 4
2 3 3
3 1 7
3 4 1
4 1 5
4 3 12
*/
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
struct data{int to,next,w;}e[100005];
int d[10000],ct[100000];
bool flag[10000];
queue<int>q;
int n,m;int head[10000];
int cnt;
bool spfa(int s){
memset(d,63,sizeof(d));
d[s]=0;
q.push(s);
flag[s]=1;//s不能同时在队列中存在两次
ct[s]++; //负权回路 ct[s]不超过n-1
while(!q.empty()){
int k=q.front();
q.pop();
flag[k]=0;
for(int i=head[k];i;i=e[i].next){
int kk=e[i].to;
if(d[kk]>d[k]+e[i].w){
d[kk]=d[k]+e[i].w;
if(!flag[kk])
{
q.push(kk);
flag[kk]=1;
ct[kk]++;
if(ct[kk]>=n) return false;
}
}
}
}
return true;
}
int main(){
scanf("%d%d",&n,&m);;
for(int i=1;i<=m;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
e[++cnt].to=y;e[cnt].w=z;e[cnt].next=head[x];head[x]=cnt;
}
if(spfa(1))
for(int i=1;i<=n;i++)
printf("%d ",d[i]);
else printf("有负权回路");
return 0;
}