最短路总结
朴素最短路。
告诉你图的点,和拥有的边,求两点最短路。我们只要把图存到邻接表或者邻接矩阵中,然后用dijkstra或者spfa来操作这个矩阵就可以得到起点到终点的最短路了。
spfa:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#define inf 100000000
using namespace std;
int len[102], mp[102][102];
int adjmp[102][102];
int n, m;
void Read(int &a){
char ch;
a = 0;
ch = getchar();
while( !(ch >= '0' && ch <= '9') ) ch = getchar();
while((ch >= '0' && ch <= '9') ){
a = a * 10 + ch - '0';
ch = getchar();
}
}
void init(){
int i, j;
int a, b, c;
memset(mp, 0, sizeof(mp));
memset(len, 0, sizeof(len));
for(i=0; i<m; ++i){
Read(a);
Read(b);
Read(c);
adjmp[a][len[a]++] = b;
adjmp[b][len[b]++] = a;
mp[a][b] = mp[b][a] = c;
}
}
void spfa(){
int i, j, u, v;
int MinDis[102];
bool mark[102];
queue<int> Q;
memset(mark, 0, sizeof(mark));
for(i=0; i<102; ++i) MinDis[i] = inf;
MinDis[1] = 0;
Q.push(1);
mark[1] = 1;
while(!Q.empty()){
u = Q.front();
Q.pop();
for(i=0; i<len[u]; ++i){
v = adjmp[u][i];
if(MinDis[v] > MinDis[u] + mp[u][v]){
MinDis[v] = MinDis[u] + mp[u][v];
if(!mark[v]){
Q.push(v);
}
}
}
}
printf("%d\n", MinDis[n]);
}
int main(){
// freopen("c:/aaa.txt", "r", stdin);
while(scanf("%d %d", &n, &m)!=EOF){
if(n==0 && m==0) break;
init();
spfa();
}
return 0;
}
dijkstra:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int mp[110][110];
int n, m;
const int inf = 999999999;
void init(){
int i, j, a, b, c;
for(i=1; i<=n; ++i){
for(j=1; j<=n; ++j){
mp[i][j] = inf;
}
}
for(i=1; i<=m; ++i){
scanf("%d %d %d", &a, &b, &c);
if(c < mp[a][b]) mp[a][b] = mp[b][a] = c;
}
}
void dijkstra(){
int i, j;
int dis[110], min, v, total;
bool mark[110];
for(i=1; i<=n; ++i){
dis[i] = mp[1][i];
mark[i] = 0;
}
dis[1] = 0;
mark[1] = 1;
total = 0;
for(i=1; i<n; ++i){
min = inf;
for(j=1; j<=n; ++j){
if(!mark[j] && dis[j] < min){
min = dis[j];
v = j;
}
}
mark[v] = 1;
total += min;
for(j=1; j<=n; ++j){
if(!mark[j] && dis[j] > min + mp[j][v]){
dis[j] = min + mp[j][v];
}
}
}
printf("%d\n", dis[n]);
}
int main(){
// freopen("c:/aaa.txt", "r", stdin);
while(scanf("%d %d", &n, &m)!=EOF){
if(n==0 && m==0) break;
init();
dijkstra();
}
return 0;
}
变形一:边加一个花费属性,求在满足最短路的情况下,使得花费也最短。
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
typedef __int64 lld;
struct Node {
lld distance, cost;
};
lld inf = 0xffffffff;
int n, m, s, t;
Node f[1005][1005];
vector<int> vec[1005];
lld Mind[1005], Minc[1005];
void spfa() {
int i, u, v, sz;
bool mark[1050];
queue<int> Q;
for( i=1; i<=n; ++i ) {
Mind[i] = inf;
Minc[i] = inf;
mark[i] = 0;
}
Q.push( s );
mark[s] = 1;
Mind[s] = Minc[s] = 0;
while( !Q.empty() ) {
u = Q.front();
Q.pop();
mark[u] = 0;
sz = vec[u].size();
for( i=0; i<sz; ++i ) {
v = vec[u][i];
if( Mind[v] > Mind[u] + f[u][v].distance) {
Mind[v] = Mind[u] + f[u][v].distance;
Minc[v] = Minc[u] + f[u][v].cost;
if( !mark[v] ) {
mark[v] = 1;
Q.push(v);
}
} else if( Mind[v] == Mind[u] + f[u][v].distance && Minc[v] > Minc[u] + f[u][v].cost ) {
Minc[v] = Minc[u] + f[u][v].cost;
if( !mark[v] ) {
mark[v] = 1;
Q.push(v);
}
}
}
}
}
int main() {
// freopen( "c:/aaa.txt", "r", stdin);
int i, j, a, b, c, d;
while( scanf( "%d %d", &n, &m ) == 2 ) {
if( n == 0 && m == 0 ) break;
for( i=1; i<=n; ++i ) {
vec[i].clear();
for( j=1; j<=n; ++j ) {
f[i][j].distance = f[i][j].cost = inf;
}
}
for( i=1; i<=m; ++i ) {
scanf( "%d %d %d %d", &a, &b, &c, &d );
vec[a].push_back( b );
vec[b].push_back( a );
if( c < f[a][b].distance ) {
f[a][b].distance = f[b][a].distance = c;
f[a][b].cost = f[b][a].cost = d;
} else if( c == f[a][b].distance && d < f[a][b].cost ) f[a][b].cost = f[b][a].cost = d;
}
scanf( "%d %d", &s, &t );
spfa();
printf( "%I64d %I64d\n", Mind[t], Minc[t] );
}
return 0;
}
变形二:图中每个点有个权值,边没有权值,求从起点到终点路线中,各点权值累加和最大。并输出路径。
这里涉及到将点的权值转换为边的权值,例如:点a的权值为x,存在一条边e( b -> a ),则边e的权值为a的权值。 然后求最短路。
在求路径时:
如果用Floyd算法的话,用一个二维数组path[][]保存路径,并初始化为指定的空值,在递归输出路径时如果碰到空值,就证明输出结束。具体的做法是这样的,比如我们可以初始化为path[a][b] = -1,经过最短路算法后,path[a][b] = c,表明从a到b中要经过c,而且c->b是最后一步,即a->.....->b->c。
如果用spfa的话,路径的保存用一维的数组就可以了,path[]。path[a] = b,表明有条边b->a,即a的父亲为b。
code :
Floyd
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 105;
int n, mp[maxn][maxn], path[maxn][maxn], val[maxn], ca=1;
void init() {
int i, j, m;
scanf( "%d", &n );
for( i=1; i<=n; ++i ) scanf( "%d", &val[i] );
val[++n] = 0;
for( i=1; i<=n; ++i ) {
for( j=1; j<=n; ++j ) {
mp[i][j] = -1;
path[i][j] = -1;
}
}
scanf( "%d", &m );
while( m-- ) {
int a, b;
scanf( "%d %d", &a, &b );
if( mp[a][b] + 1 ) continue;
mp[a][b] = val[b];
}
}
void Print( int s, int e ) {
if( path[s][e] + 1 == 0 ) {
printf( "%d->%d", s, e );
return;
}
Print( s, path[s][e] );
printf( "->%d", e == n ? 1 : e );
}
void solve() {
int i, j, k;
for( k=1; k<=n; ++k ) {
for( i=1; i<=k; ++i ) {
for( j=k; j<=n; ++j ) {
if( mp[i][k]+1 && mp[k][j]+1 && mp[i][k]+mp[k][j] > mp[i][j] ) {
mp[i][j] = mp[i][k]+mp[k][j];
path[i][j] = k;
}
}
}
}
if( ca != 1 ) printf( "\n" );
printf( "CASE %d#\npoints : %d\n", ca++, mp[1][n] );
printf( "circuit : " );
Print( 1, n );
printf( "\n" );
}
int main() {
// freopen( "c:/aaa.txt", "r", stdin );
int T;
scanf( "%d", &T );
while( T-- ) {
init();
solve();
}
return 0;
}
spfa:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
const int maxn = 105;
int n, mp[maxn][maxn], val[maxn], ca=1;
int path[maxn];
void init() {
int i, j, m;
scanf( "%d", &n );
for( i=1; i<=n; ++i ) scanf( "%d", &val[i] );
val[++n] = 0;
for( i=1; i<=n; ++i ) {
for( j=1; j<=n; ++j ) {
mp[i][j] = -1;
}
}
scanf( "%d", &m );
while( m-- ) {
int a, b;
scanf( "%d %d", &a, &b );
if( mp[a][b] + 1 ) continue;
mp[a][b] = val[b];
}
}
void Print( int e ) {
if( e == 1 ) {
printf( "1" );
return;
}
Print( path[e] );
printf( "->%d", e == n ? 1 : e );
}
void solve() {
queue<int> Q;
bool mark[maxn];
int Max[maxn], i, u;
for( i=1; i<=n; ++i ) {
mark[i] = 0;
Max[i] = -1;
path[i] = i;
}
Max[1] = 0;
Q.push( 1 );
mark[1] = 1;
while( !Q.empty() ) {
u = Q.front();
Q.pop();
mark[u] = 0;
for( i=1; i<=n; ++i ) {
if( mp[u][i]+1 && mp[u][i]+Max[u]>Max[i] ) {
Max[i] = mp[u][i]+Max[u];
path[i] = u;
if( !mark[i] ) {
Q.push( i );
mark[i] = 1;
}
}
}
}
if( ca != 1 ) printf( "\n" );
printf( "CASE %d#\npoints : %d\n", ca++, Max[n] );
printf( "circuit : " );
Print( n );
printf( "\n" );
}
int main() {
// freopen( "c:/aaa.txt", "r", stdin );
int T;
scanf( "%d", &T );
while( T-- ) {
init();
solve();
}
return 0;
}
两个注意的地方:
1.根据求最短路或者最长路,将图的邻接表初始化相应的极限值,求最短路则初始化最大,求最长路初始化为最小指,一般如果不存在负边,我们可以初始化为-1.
2.要考虑是否存在重边的情况。
.
浙公网安备 33010602011771号