模板题,注意输入顺序是先
t
t
t 后
n
n
n
#include <iostream>
#include <queue>
#include <cstring>
using namespace std;
const int MAXN = 1005 ;
struct st{
int ID;
int val;
friend bool operator < ( st x, st y) {
return x. val > y. val;
}
} ;
struct Edge{
int next;
int to;
int val;
} edge[ 200000 ] ;
int cnt;
int head[ MAXN] ;
int vis[ MAXN] ;
int dis[ MAXN] ;
void Add_Edge ( int u, int v, int w) {
edge[ cnt] . next = head[ u] ;
edge[ cnt] . to = v;
edge[ cnt] . val = w;
head[ u] = cnt++ ;
}
void dijstra ( int s) {
priority_queue< st> q;
st now;
now. ID = s;
dis[ s] = 0 ;
now. val = dis[ s] ;
q. push ( now) ;
while ( ! q. empty ( ) ) {
st u = q. top ( ) ;
q. pop ( ) ;
if ( vis[ u. ID] ) continue ;
vis[ u. ID] = 1 ;
for ( int i= head[ u. ID] ; i!= - 1 ; i= edge[ i] . next) {
if ( dis[ u. ID] + edge[ i] . val < dis[ edge[ i] . to] && ! vis[ edge[ i] . to] ) {
dis[ edge[ i] . to] = dis[ u. ID] + edge[ i] . val;
now. ID = edge[ i] . to;
now. val = dis[ edge[ i] . to] ;
q. push ( now) ;
}
}
}
}
int main ( ) {
int t, n, u, v, w;
cin >> t >> n;
memset ( dis, 0x3f , sizeof dis) ;
memset ( head, - 1 , sizeof head) ;
for ( int i= 0 ; i< t; i++ ) {
cin >> u >> v >> w;
Add_Edge ( u, v, w) ;
Add_Edge ( v, u, w) ;
}
dijstra ( 1 ) ;
cout << dis[ n] ;
return 0 ;
}
题意:有两只青蛙,分别在一号和二号位置,现在一号青蛙想到二号青蛙的位置上去,借助其他位置,问到达二号位置的过程中每次跳跃的最短跳跃距离 数据范围比较小,求出所有石头两两之间距离,更改
d
i
j
s
t
r
a
dijstra
d i j s t r a 算法的判断条件为取当前最短距离和需要跳跃的距离之间的最大值
#include <iostream>
#include <queue>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
const int MAXN = 1005 ;
struct st{
int ID;
double val;
friend bool operator < ( st x, st y) {
return x. val > y. val;
}
} ;
struct Edge{
int next;
int to;
double val;
} edge[ 200000 ] ;
struct NODE{
int x, y;
} node[ MAXN] ;
int cnt;
int head[ MAXN] ;
int vis[ MAXN] ;
double dis[ MAXN] ;
void Add_Edge ( int u, int v, double w) {
edge[ cnt] . next = head[ u] ;
edge[ cnt] . to = v;
edge[ cnt] . val = w;
head[ u] = cnt++ ;
}
void dijstra ( int s) {
priority_queue< st> q;
st now;
now. ID = s;
dis[ s] = 0 ;
now. val = dis[ s] ;
q. push ( now) ;
while ( ! q. empty ( ) ) {
st u = q. top ( ) ;
q. pop ( ) ;
if ( vis[ u. ID] ) continue ;
vis[ u. ID] = 1 ;
for ( int i= head[ u. ID] ; i!= - 1 ; i= edge[ i] . next) {
if ( max ( dis[ u. ID] , edge[ i] . val) < dis[ edge[ i] . to] && ! vis[ edge[ i] . to] ) {
dis[ edge[ i] . to] = max ( dis[ u. ID] , edge[ i] . val) ;
now. ID = edge[ i] . to;
now. val = dis[ edge[ i] . to] ;
q. push ( now) ;
}
}
}
}
int main ( ) {
int t, n, u, v, x, y;
double w;
int num = 1 ;
while ( cin >> n && n) {
for ( int i= 1 ; i<= n; i++ ) dis[ i] = 999999999.0 ;
memset ( head, - 1 , sizeof head) ;
memset ( vis, 0 , sizeof vis) ;
for ( int i= 1 ; i<= n; i++ ) {
cin >> x >> y;
node[ i] . x = x;
node[ i] . y = y;
}
for ( int i= 1 ; i<= n; i++ ) {
for ( int j= 1 ; j<= n; j++ ) {
Add_Edge ( i, j, sqrt ( ( node[ i] . x - node[ j] . x) * ( node[ i] . x - node[ j] . x) + ( node[ i] . y - node[ j] . y) * ( node[ i] . y - node[ j] . y) ) ) ;
Add_Edge ( j, i, sqrt ( ( node[ i] . x - node[ j] . x) * ( node[ i] . x - node[ j] . x) + ( node[ i] . y - node[ j] . y) * ( node[ i] . y - node[ j] . y) ) ) ;
}
}
dijstra ( 1 ) ;
printf ( "Scenario #%d\n" , num++ ) ;
printf ( "Frog Distance = %.3f\n\n" , dis[ 2 ] ) ;
}
return 0 ;
}
给出每条路的最大允许载重量,要求从位置
1
1
1 到位置
n
n
n 所经过的路径中最大的允许重量,如果1到2最大载重量为3,2到3最大载重量为5,1到3最大载重量为4,那么因为有两条路径能够到达位置n,所以经过2的路径最多只能载重3;而直接到3的最大载重量为4,综合这两条路径,所以总的最大载重量为4 同样是最短路的变形问题,在每一个点扩展的过程中每次找从起点到当前点载重量的最小值,这是这个点的最大载重量,最后需要取整体最大的载重量,优先级应为从大到小
#include <iostream>
#include <queue>
#include <cstring>
#include <cmath>
#include <cstdio>
using namespace std;
const int MAXN = 1e3 + 100 ;
struct st{
int ID;
int val;
bool operator < ( st x) const {
return val < x. val;
}
} ;
struct Edge{
int next;
int to;
int val;
} edge[ 200000 ] ;
int head[ MAXN] ;
int vis[ MAXN] ;
int dis[ MAXN] ;
int cnt;
void Add_Edge ( int u, int v, int w) {
edge[ cnt] . to = v;
edge[ cnt] . next = head[ u] ;
edge[ cnt] . val = w;
head[ u] = cnt++ ;
}
void dijstra ( int s) {
priority_queue< st> q;
st now;
dis[ s] = 0x3f3f3f3f ;
now. ID = s;
now. val = dis[ s] ;
q. push ( now) ;
while ( ! q. empty ( ) ) {
st u = q. top ( ) ;
q. pop ( ) ;
if ( vis[ u. ID] ) continue ;
vis[ u. ID] = 1 ;
for ( int i= head[ u. ID] ; i != - 1 ; i = edge[ i] . next) {
if ( ! vis[ edge[ i] . to] && min ( dis[ u. ID] , edge[ i] . val) > dis[ edge[ i] . to] ) {
dis[ edge[ i] . to] = min ( dis[ u. ID] , edge[ i] . val) ;
now. ID = edge[ i] . to;
now. val = dis[ edge[ i] . to] ;
q. push ( now) ;
}
}
}
}
int main ( ) {
int t, n, m, u, v, w;
scanf ( "%d" , & t) ;
for ( int j= 1 ; j<= t; j++ ) {
memset ( head, - 1 , sizeof head) ;
memset ( vis, 0 , sizeof vis) ;
memset ( dis, - 0x3f , sizeof dis) ;
cnt = 0 ;
scanf ( "%d%d" , & n, & m) ;
for ( int i= 0 ; i< m; i++ ) {
scanf ( "%d%d%d" , & u, & v, & w) ;
Add_Edge ( u, v, w) ;
Add_Edge ( v, u, w) ;
}
dijstra ( 1 ) ;
printf ( "Scenario #%d:\n" , j) ;
printf ( "%d\n\n" , dis[ n] ) ;
}
return 0 ;
}
有
n
n
n 头奶牛,分别在
1
−
n
1-n
1 − n 号农场,现在在
X
X
X 号农场要开一个晚会,道路是有向的,问这些奶牛到达农场再回来要经过的最短路 数组开小一些防止
m
e
m
s
e
t
memset
m e m s e t 时间过慢,直接跑
n
n
n 次最短路,最后分别求奶牛的最短路取最大值即可
#include <iostream>
#include <cstdio>
#include <map>
#include <algorithm>
#include <queue>
#include <cstring>
using namespace std;
const int MAXN = 1e3 + 100 ;
struct st{
int ID;
int val;
bool operator < ( st x) const {
return val > x. val;
}
} ;
struct Edge{
int next;
int to;
int val;
} edge[ 200000 ] ;
int head[ MAXN] ;
int vis[ MAXN] ;
int dis[ MAXN] ;
int cnt;
void Add_Edge ( int u, int v, int w) {
edge[ cnt] . next = head[ u] ;
edge[ cnt] . to = v;
edge[ cnt] . val = w;
head[ u] = cnt++ ;
}
map< int , int > mp;
void dijstra ( int s) {
priority_queue< st> q;
st now;
dis[ s] = 0 ;
now. ID = s;
now. val = dis[ s] ;
q. push ( now) ;
while ( ! q. empty ( ) ) {
st u = q. top ( ) ;
q. pop ( ) ;
if ( vis[ u. ID] ) continue ;
vis[ u. ID] = 1 ;
for ( int i= head[ u. ID] ; i!= - 1 ; i= edge[ i] . next) {
if ( ! vis[ edge[ i] . to] && dis[ u. ID] + edge[ i] . val < dis[ edge[ i] . to] ) {
dis[ edge[ i] . to] = dis[ u. ID] + edge[ i] . val;
now. ID = edge[ i] . to;
now. val = dis[ edge[ i] . to] ;
q. push ( now) ;
}
}
}
}
int main ( ) {
int n, m, x, u, v, w;
scanf ( "%d%d%d" , & n, & m, & x) ;
memset ( head, - 1 , sizeof head) ;
memset ( dis, 0x3f , sizeof dis) ;
while ( m-- ) {
scanf ( "%d%d%d" , & u, & v, & w) ;
Add_Edge ( u, v, w) ;
}
dijstra ( x) ;
for ( int i= 1 ; i<= n; i++ ) {
mp[ i] = dis[ i] ;
}
int ans = - 0x3f3f3f3f ;
for ( int i= 1 ; i<= n; i++ ) {
if ( i == x) continue ;
memset ( dis, 0x3f , sizeof dis) ;
memset ( vis, 0 , sizeof vis) ;
dijstra ( i) ;
ans = max ( ans, mp[ i] + dis[ x] ) ;
}
cout << ans;
return 0 ;
}
题目描述了一个情景,告诉我们用A换B的汇率和佣金,现在问经过兑换,最后需要换回原来的币种,能不能换完之后发现钱变多了 问题明显是求正环的问题,使用
b
e
l
l
m
a
n
−
f
o
r
d
bellman-ford
b e l l m a n − f o r d 算法求解,我们进行
∣
V
∣
−
1
|V|-1
∣ V ∣ − 1 次松弛操作,记录现在的结果,然后重新跑一边
b
e
l
l
m
a
n
−
f
o
r
d
bellman-ford
b e l l m a n − f o r d ,这时候如果没正环,应该是最大的情况,如果发现又变大了,只能说明图中存在正环
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int INF = 0x3f3f3f3f ;
const int MAXN = 1e6 + 100 ;
const double eps = 1e-6 ;
int Data[ MAXN] ;
double edge1[ 200 ] [ 200 ] ;
double edge2[ 200 ] [ 200 ] ;
double dis[ 200 ] ;
bool Bellman_Ford ( int n) {
double d[ 200 ] ;
for ( int i= 1 ; i<= n; i++ ) {
d[ i] = dis[ i] ;
}
for ( int k= 1 ; k< n; k++ ) {
for ( int i= 1 ; i<= n; i++ ) {
for ( int j= 1 ; j<= n; j++ ) {
if ( dis[ j] < ( dis[ i] - edge2[ i] [ j] ) * edge1[ i] [ j] ) {
dis[ j] = ( dis[ i] - edge2[ i] [ j] ) * edge1[ i] [ j] ;
}
}
}
}
for ( int i= 1 ; i<= n; i++ ) {
if ( d[ i] < dis[ i] ) return true ;
}
return false ;
}
int main ( ) {
int n, m, s, u, x, y;
double v;
double rab, rba, cab, cba;
scanf ( "%d%d%d%lf" , & n, & m, & s, & v) ;
dis[ s] = v;
while ( m-- ) {
scanf ( "%d%d%lf%lf%lf%lf" , & x, & y, & rab, & cab, & rba, & cba) ;
edge1[ x] [ y] = rab;
edge1[ y] [ x] = rba;
edge2[ x] [ y] = cab;
edge2[ y] [ x] = cba;
}
Bellman_Ford ( n) ;
if ( Bellman_Ford ( n) ) printf ( "YES" ) ;
else printf ( "NO" ) ;
return 0 ;
}
给出一些路径,农场之间的路径是双向的,虫洞是单向的,进入虫洞会使时间倒退,走正常的路会消耗时间,问有没有可能在从某个地方出发之前到达该地方 如果把进入虫洞的时间设为负值,那么这就是一个判断有没有负环的问题,可以使用
B
e
l
l
m
a
n
−
f
o
r
d
Bellman-ford
B e l l m a n − f o r d 和
f
l
o
y
d
floyd
f l o y d 两种方法 黑书上介绍的是
f
l
o
y
d
floyd
f l o y d 方法,思路是令
e
d
g
e
[
i
]
[
i
]
=
0
edge[i][i]=0
e d g e [ i ] [ i ] = 0 ,之后跑一遍
f
l
o
y
d
floyd
f l o y d ,如果发现对于某个
i
i
i ,从
i
i
i 到
i
i
i 时间为负数,说明有负环,但是时间复杂度很高,需要在
f
l
o
y
d
floyd
f l o y d 加一个小小的优化,剪掉路径不存在的情况 我写的朴素
b
e
l
l
m
a
n
−
f
o
r
d
bellman-ford
b e l l m a n − f o r d 没通过,但是思路是清晰的
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int INF = 0x3f3f3f3f ;
const int MAXN = 1e6 + 100 ;
const double eps = 1e-6 ;
int Data[ MAXN] ;
int edge[ 600 ] [ 600 ] ;
bool floyd ( int n) {
for ( int k= 1 ; k<= n; k++ ) {
for ( int i= 1 ; i<= n; i++ ) {
if ( edge[ i] [ k] != INF)
for ( int j= 1 ; j<= n; j++ ) {
if ( edge[ i] [ j] > edge[ i] [ k] + edge[ k] [ j] ) {
edge[ i] [ j] = edge[ i] [ k] + edge[ k] [ j] ;
}
}
}
}
for ( int i= 1 ; i<= n; i++ ) {
if ( edge[ i] [ i] < 0 ) return true ;
}
return false ;
}
int main ( ) {
int F, n, m, w, s, e, t;
scanf ( "%d" , & F) ;
while ( F-- ) {
scanf ( "%d%d%d" , & n, & m, & w) ;
memset ( edge, INF, sizeof edge) ;
while ( m-- ) {
scanf ( "%d%d%d" , & s, & e, & t) ;
if ( t < edge[ s] [ e] ) {
edge[ s] [ e] = edge[ e] [ s] = t;
}
}
while ( w-- ) {
scanf ( "%d%d%d" , & s, & e, & t) ;
edge[ s] [ e] = min ( - t, edge[ s] [ e] ) ;
}
for ( int i= 1 ; i<= n; i++ ) edge[ i] [ i] = 0 ;
if ( floyd ( n) ) printf ( "YES" ) ;
else printf ( "NO" ) ;
printf ( "\n" ) ;
}
return 0 ;
}
给出若干组比赛结果,格式为
A
B
A\ \ B
A B ,表示
A
A
A 赢了
B
B
B ,问有几个能够确定的名次 如果想确定名次,必须要知道他和其他所有人的比赛结果,可以利用
f
l
o
y
d
floyd
f l o y d 的递推关系,对于
A
,
B
,
C
A,B,C
A , B , C 如果
A
A
A 赢了
B
B
B ,那么令
e
d
g
e
[
A
]
[
B
]
=
1
,
e
d
g
e
[
B
]
[
A
]
=
−
1
edge[A][B]=1,edge[B][A]=-1
e d g e [ A ] [ B ] = 1 , e d g e [ B ] [ A ] = − 1 ,如果
e
d
g
e
[
B
]
[
C
]
=
1
edge[B][C]=1
e d g e [ B ] [ C ] = 1 那么就可以推出
e
d
g
e
[
A
]
[
C
]
=
1
edge[A][C]=1
e d g e [ A ] [ C ] = 1 ,进而推出所有人的比赛结果,最后计数
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int INF = 0x3f3f3f3f ;
const int MAXN = 1e6 + 100 ;
const double eps = 1e-6 ;
int Data[ MAXN] ;
int edge[ 200 ] [ 200 ] ;
void floyd ( int n) {
for ( int k= 1 ; k<= n; k++ ) {
for ( int i= 1 ; i<= n; i++ ) {
for ( int j= 1 ; j<= n; j++ ) {
if ( edge[ i] [ k] == edge[ k] [ j] && edge[ i] [ k] != INF) {
edge[ i] [ j] = edge[ i] [ k] ;
}
}
}
}
}
int main ( ) {
int n, m, u, v;
cin >> n >> m;
memset ( edge, INF, sizeof edge) ;
while ( m-- ) {
cin >> u >> v;
edge[ u] [ v] = 1 ;
edge[ v] [ u] = - 1 ;
}
floyd ( n) ;
int ans = 0 ;
for ( int i= 1 ; i<= n; i++ ) {
int num = 0 ;
for ( int j= 1 ; j<= n; j++ ) {
if ( i == j) continue ;
if ( edge[ i] [ j] != INF) num++ ;
}
if ( num == n - 1 ) ans++ ;
}
cout << ans;
return 0 ;
}