单源无负权最短路:Dijkstra
多源无负权最短路:Floyd
单源负权最短路:Bellman-ford,SPFA
以hdu 2544为例
Dijkstra
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> par;
const int maxv = 1e5+5;
const int inf = 1000000000;
struct Node{
int v,dis;
Node(){}
Node(int v,int dis) : v(v),dis(dis){}
bool operator <(const Node &a)const{
return dis > a.dis;
}
};
vector<Node> node[maxv];
int dis[maxv];
bool vis[maxv] = {false};
priority_queue<Node> q;
int n,m,u,v,w;
void Dijkstra(int s){
fill(dis,dis+maxv,inf);
fill(vis,vis+maxv,false);
dis[s] = 0;
q.push(Node(s,0));
Node st;
while(!q.empty()){
st = q.top();q.pop();
if(vis[st.v]) continue;
vis[st.v] = true;
for(int j = 0; j < node[st.v].size(); j++){
int v = node[st.v][j].v;
if(!vis[v] && dis[v] > node[st.v][j].dis + dis[st.v]){
dis[v] = node[st.v][j].dis + dis[st.v];
q.push(Node(v,dis[v]));
}
}
}
}
int main(){
while(scanf("%d%d",&n,&m),n || m){
for(int i = 0; i < maxv; i++){
node[i].clear();
}
for(int i = 0; i < m; i++){
scanf("%d%d%d",&u,&v,&w);
node[u].push_back(Node(v,w));
node[v].push_back(Node(u,w));
}
int st,ed;
Dijkstra(1);
printf("%d\n",dis[n]);
}
}
Floyd
#include<bits/stdc++.h>
using namespace std;
const int maxn = 10002;
const int inf = 0x3fffffff;
struct Node {
int v, dis; // v表示邻接边的目的顶点,dis表示邻边的权
Node(int v,int dis):v(v),dis(dis){}
};
int d[maxn][maxn];
int n,m,u,v,val;
void Floyd(){
for(int k = 1; k <= n; k++){
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n; j++){
if(d[i][j] != inf && d[k][j] != inf && d[i][k] + d[k][j] < d[i][j]){
d[i][j] = d[i][k] + d[j][k];
}
}
}
}
}
int main(){
scanf("%d%d",&n,&m);
fill(d[0],d[0] + maxn*maxn,inf);
for(int i = 0; i < m; i++){
scanf("%d%d%d",&u,&v,&val);
d[u][v] = d[v][u] = val;
}
Floyd();
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n; j++){
printf("%d ",d[i][j]);
}
printf("\n");
}
}
注意:hdu2544会内存超限
Bellman-ford:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 100000;
const int inf = 0x3fffffff;
struct Node{
int v,dis;
Node(int v,int dis):v(v),dis(dis){}
};
vector<Node> Adj[maxn];
int n,m,u,v,val;
int d[maxn+5];
bool bellman(int s){
fill(d,d+maxn,inf);
d[s] = 0;
for(int i = 0; i < n - 1 ; i++){
for(int u = 1; u <= n; u++){
for(int j = 0; j < Adj[u].size(); j++){
int v = Adj[u][j].v;
int dis = Adj[u][j].dis;
if(d[v] > dis + d[u]) d[v] = dis + d[u];
}
}
}
// 以下为判断负环的代码负环的意思是一个环的权值加起来为负值
for(int u = 1; u <= n; u++){
for(int j = 0; j < Adj[u].size(); j++){
int v = Adj[u][j].v;
int dis = Adj[u][j].dis;
if(d[u] + dis < d[v]){//仍然可以松弛
return false;
}
}
}
return true;
}
int main(){
scanf("%d%d",&n,&m);
for(int i = 0; i < maxn; i++) Adj[i].clear();
for(int i = 0; i < m; i++){
scanf("%d%d%d",&u,&v,&val);
Adj[u].push_back(Node(v,val));
Adj[v].push_back(Node(u,val));
}
bellman(1);
printf("%d\n",d[n]);
}
SPFA:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 100000;
const int inf = 0x3fffffff;
struct Node {
int v, dis; // v表示邻接边的目的顶点,dis表示邻边的权
Node(int v,int dis):v(v),dis(dis){}
};
vector<Node> adj[maxn]; //adj为邻接表
int d[maxn],num[maxn];//起点到各个点的距离 num记录顶点的入队次数
bool inq[maxn]; //顶点是否在队列中
int n,m,u,v,val;
bool spfa(int s) {
//初始化
memset(inq, false, sizeof(inq));
memset(num, 0, sizeof(num));
fill(d, d + maxn, inf);
//源点入队
queue<int> q;
q.push(s);
inq[s] = true;//源点已入队
num[s]++;//源点入队数加1
d[s] = 0;
//主体
while (!q.empty()) {
int u = q.front();
q.pop();
inq[u] = false;
for (int j = 0; j < adj[u].size(); j++) {
int v = adj[u][j].v;
int dis = adj[u][j].dis;
if (d[u] + dis < d[v]) {
d[v] = d[u] + dis;
if (!inq[v]) {
q.push(v);
inq[v] = true;
num[v]++;
if (num[v] >= n) return false; // 有负环
}
}
}
}
return true;
}
int main(){
while(scanf("%d%d",&n,&m),m || n){
for(int i = 0; i < maxn; i++) adj[i].clear();
for(int i = 0; i < m; i++){
scanf("%d%d%d",&u,&v,&val);
adj[u].push_back(Node(v,val));
adj[v].push_back(Node(u,val));
}
spfa(1);
printf("%d\n",d[n]);
}
}