1.floyd算法
可以预处理出任意点之间的最短路,如果最短路的起点和终点总是改变,用这个比较方便
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
mp[i][j]=min(mp[i][j],mp[i][k]+mp[k][j]);
2.Dijstra算法:
堆优化的可以解决从a点出发去任意点的最短路径,无法处理含负权边的图
dijstra算法堆优化:(模板题)链接:https://www.luogu.org/problem/P3371
#include
#define ll long long
#define inf 2147483647
#define MAXN 500005
using namespace std;
int to[MAXN<<1],head[MAXN<<1],nxt[MAXN<<1],val[MAXN<<1];
int tot=0;
ll dis[MAXN];
int vis[MAXN];
void init()
{
tot=0;
memset(head,-1,sizeof(head));
}
void add(int u,int v,int w)
{
to[++tot]=v;
val[tot]=w;
nxt[tot]=head[u];
head[u]=tot;
}
struct node
{
int v;
ll dis;
friend bool operator<(node a,node b)
{
return a.dis>b.dis;
}
};
void dij(int st,int n)
{
for(int i=0;i que;
que.push(node{st,0});
while(que.size())
{
int u=que.top().v;
que.pop();
if(vis[u]==1)
continue;
vis[u]=1;
for(int i=head[u];~i;i=nxt[i])
{
int v=to[i];
if(dis[u]+val[i]
输出路径
用pre[]保存路径,如果更新了u->v,呢么最后一次v被更新,即为到v的路径
//更新路径的时候,pre[v]=u;
void print(int x,int y)
{
int u=x,v=y;
printf("%d",u);
while(u!=v)
{
printf("->%d",pre[u]);
u=pre[u];
}
printf("\n");
}
3,SPFA算法:
如果图中含有负权边,呢么我们用spfa算法(广搜)解决:
#include
#define ll long long
#define MAXN 1000005
using namespace std;
int to[MAXN<<1],nxt[MAXN<<1],head[MAXN<<1],val[MAXN<<1];
int tot=0;
ll dis[MAXN];
void init()
{
memset(head,0,sizeof(head));
tot=0;
}
void add(int u,int v,int w)
{
to[++tot]=v;
nxt[tot]=head[u];
val[tot]=w;
head[u]=tot;
}
void spfa(int st,int n)
{
for(int i=0;i<=n;i++)
dis[i]=1e18;
queue que;
dis[st]=0;
que.push(st);
while(que.size())
{
int u=que.front();
que.pop();
for(int i=head[u];i;i=nxt[i])
{
int v=to[i];
if(dis[u]+val[i]
判负环:如果图中存在负环,spfa会一直进行下去,一般判负环的题
https://www.luogu.org/problem/P3385
#include
#define ll long long
#define MAXN 20005
using namespace std;
int to[MAXN<<1],nxt[MAXN<<1],head[MAXN<<1],val[MAXN<<1];
int tot=0,sign;
int vis[MAXN];
int n,dis[MAXN],cnt[MAXN];
void init()
{
sign=tot=0;
for(int i=0;i<=MAXN;i++)
cnt[i]=vis[i]=head[i]=0,dis[i]=1e9;
}
void add(int u,int v,int w)
{
to[++tot]=v;
nxt[tot]=head[u];
val[tot]=w;
head[u]=tot;
}
int spfa()
{
queue q;
q.push(1);
dis[1]=0;
while(!q.empty())
{
if(dis[q.front()]>dis[q.back()])
swap(q.front(),q.back());
int u=q.front();
q.pop();
vis[u]=0;
for(int i=head[u];i;i=nxt[i])
{
int v=to[i];
if(dis[v]>dis[u]+val[i])
{
dis[v]=dis[u]+val[i];
cnt[v]=cnt[u]+1;
if(cnt[v]>n)
return 1;
if(!vis[v])
{
vis[v]=1;
q.push(v);
}
}
}
}
return 0;
}
int main()
{
int m,t,u,v,w;
scanf("%d",&t);
while(t--)
{
init();
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
if(w>=0)
add(v,u,w);
}
if(spfa())
printf("YE5\n");
else
printf("N0\n");
}
return 0;
}
k短路算法(A* 算法)
(沈阳网络赛):
#include
#define maxn 1005
#define maxe 100005
using namespace std;
struct State{
int f,g,u; // f=g+dis dis表示当前点到终点的最短路径,即之前的预处理,g表示到当前点的路径长度
bool operator<(const State b)const{
if(f==b.f)return g>b.g;
return f>b.f;
}
};
struct Edge{
int v,w,next;
}edge[maxe],reedge[maxe];
int head[maxn],rehead[maxn];
int dis[maxn],vis[maxn];
int n,m,cot,s,t,k;
void init(){
cot=0; //cot代表边的id 每条边的id都不相同
memset(head,-1,sizeof(head));
memset(rehead,-1,sizeof(rehead));
}
void addedge(int u,int v,int w){
edge[cot]={v,w,head[u]};//记录上一次u的id是多少 这样方便遍历head[u]初始值为-1
head[u]=cot;//head[u] 给这个u标记上独一无二的id
reedge[cot]={u,w,rehead[v]};
rehead[v]=cot++;
}
void SPFA(){
queueq;
memset(vis,0,sizeof(vis));
memset(dis,-1,sizeof(dis));
int u,v;
q.push(t);
vis[t]=true;//vis表示当前点是否在队列
dis[t]=0;
while(!q.empty()){
u=q.front();
q.pop();
vis[u] = 0;//rehead[u] 是u最后一次出现的id reedge[i].ne 代表第i次出现的边上一次出现的id
for(int i=rehead[u];~i;i=reedge[i].next){ //~i取反 当i为-1时正好取反为0 退出for
v=reedge[i].v;
if(dis[v]>dis[u]+reedge[i].w || dis[v]==-1){
dis[v]=dis[u]+reedge[i].w;
if(!vis[v]){
q.push(v);
vis[v]=1;
}
}
}
}
}
int Astart(){
if(s==t)k++;
if(dis[s]==-1)return -1;
int cnt=0;
priority_queueq; // 优先队列
State a,b;
a.g=0;
a.u=s;
a.f=a.g+dis[a.u];
q.push(a);
while(!q.empty()){
b=q.top();
q.pop();
if(b.u==t){
cnt++;
if(cnt==k)return b.g;
}
for(int i=head[b.u];~i;i=edge[i].next){
a.g=b.g+edge[i].w;
a.u=edge[i].v;
a.f=a.g+dis[a.u];
q.push(a);
}
}
return -1;
}
int main()
{
int u,v,w,T;
while(scanf("%d%d",&n,&m)==2){
init();
scanf("%d%d%d%d",&s,&t,&k, &T); //起点 终点 第k条 时间T
for(int i=0;i