注意事项
1.最短路问题的难点不在于算法,而在于建图方式
2.需要挖掘题目中隐藏的条件单、双向图,是否存在负环,是否有重边等等
3.往往不只简单图论还会和其他知识点一起出
第一部分————模板
一.单源最短路
dijkstra算法
注意:边权必须为非负
1.Dijkstra求最短路 I
稠密图用邻接矩阵
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 510;
int g[N][N];
int dist[N];
bool st[N];
int n,m;
int dij()
{
memset(dist,0x3f,sizeof dist);
dist[1]=0;
for(int i=0;i<n;i++)
{
int t=-1;
for(int j=1;j<=n;j++)
{
if(!st[j]&&(t==-1||dist[t]>dist[j]))
{
t=j;
}
}
st[t]=true;
for(int j=1;j<=n;j++)
{
dist[j]=min(dist[j],dist[t]+g[t][j]);
}
}
if(dist[n]==0x3f3f3f3f)return -1;
return dist[n];
}
int main()
{
int a,b,c;
cin>>n>>m;
memset(g,0x3f,sizeof g);
while (m -- )
{
cin>>a>>b>>c;
g[a][b]=min(g[a][b],c);
}
cout<<dij()<<endl;
}
2.堆优化版的dijkstra
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int N = 1000010;
int e[N],ne[N],w[N],h[N],idx;
int n,m;
bool st[N];
int dist[N];
void add(int a,int b,int c)
{
e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
int dij()
{
priority_queue<PII, vector<PII>, greater<PII>> heap;
memset(dist,0x3f,sizeof dist);
dist[1]=0;
heap.push({0,1});
while(heap.size())
{
auto t=heap.top();
heap.pop();
int ver=t.second;
if(st[ver])continue;
st[ver]=true;
for(int i=h[ver];i!=-1;i=ne[i])
{
int j=e[i];
if(dist[j]>dist[ver]+w[i])
{
dist[j]=dist[ver]+w[i];
heap.push({dist[j],j});
}
}
}
if(dist[n]>=0x3f3f3f3f/2)return -1;
else return dist[n];
}
int main()
{
cin>>n>>m;
memset(h,-1,sizeof h);
int a,b,c;
while (m -- ){
cin>>a>>b>>c;
add(a,b,c);
}
cout<<dij()<<endl;
}
3.有边数限制的最短路 bellman-ford算法
边权可以为负数
可以用来找负环,第n次有更新的话证明有负环
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 10010;
struct Edge{
int a,b,c;
}ed[N];
int n,m,k;
int dist[N];
int last[N];
void ford()
{
memset(dist,0x3f,sizeof dist);
dist[1]=0;
for(int i=0;i<k;i++)
{
memcpy(last,dist,sizeof dist);
for(int j=0;j<m;j++)
{
auto e=ed[j];
dist[e.b]=min(dist[e.b],last[e.a]+e.c);
}
}
}
int main()
{
cin>>n>>m>>k;
int a,b,c;
for(int i=0;i<m;i++)
{
cin>>a>>b>>c;
ed[i]={a,b,c};
}
ford();
if(dist[n]>0x3f3f3f3f/2)cout<<"impossible"<<endl;
else cout<<dist[n]<<endl;
}
5.有负权求最短路 spfa算法
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 100010;
int e[N],ne[N],h[N],w[N],idx=0;
int dist[N];
bool st[N];
int n,m;
void add(int a,int b,int c)
{
e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
int spfa()
{
queue<int>q;
q.push(1);
memset(dist,0x3f,sizeof dist);
dist[1]=0;
st[1]=true;
while(q.size())
{
auto t=q.front();
q.pop();
st[t]=false;
for(int i=h[t];i!=-1;i=ne[i])
{
int j=e[i];
if(dist[j]>dist[t]+w[i])
{
dist[j]=dist[t]+w[i];
if(!st[j])
{
q.push(j);
st[j]=true;
}
}
}
}
return dist[n];
}
int main()
{
cin>>n>>m;
memset(h, -1, sizeof h);
int a,b,c;
while (m -- )
{
cin>>a>>b>>c;
add(a,b,c);
}
int res=spfa();
if(res==0x3f3f3f3f)cout<<"impossible"<<endl;
else cout<<res<<endl;
}
6.spfa求负环
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 100010;
int e[N],ne[N],w[N],h[N],idx=0;
bool st[N];
int n,m;
int dist[N];
int cnt[N];
void add(int a,int b,int c)
{
e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
bool spfa()
{
queue<int>q;
for(int i=1;i<=n;i++)
{
q.push(i);
st[i]=true;
}
while(q.size())
{
auto t=q.front();
q.pop();
st[t]=false;
for(int i=h[t];i!=-1;i=ne[i])
{
int j=e[i];
if(dist[j]>dist[t]+w[i])
{
cnt[j]=cnt[t]+1;
if(cnt[j]>=n)return true;
dist[j]=dist[t]+w[i];
if(!st[j])
{
q.push(j);
st[j]=true;
}
}
}
}
return false;
}
int main()
{
cin>>n>>m;
int a,b,c;
memset(h,-1,sizeof h);
while (m -- )
{
cin>>a>>b>>c;
add(a,b,c);
}
if(spfa())cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
二.多源汇最短路
1.floyd算法
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 210;
const int INF = 0x3f3f3f3f;
int n,m,q;
int d[N][N];
void floyd()
{
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
}
int main()
{
cin>>n>>m>>q;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(i==j)d[i][j]=0;
else d[i][j]=INF;
int a,b,c;
while (m -- )
{
cin>>a>>b>>c;
d[a][b]=min(d[a][b],c);
}
floyd();
while(q--)
{
cin>>a>>b;
int t=d[a][b];
if(t>0x3f3f3f3f/2)cout<<"impossible"<<endl;
else cout<<t<<endl;
}
}
第二部分————练习题
1.热浪----dijkstra
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
typedef pair<int, int> PII;
typedef long long LL;
const int N = 6220*2,M=2520;
int dist[M];
bool st[M];
int h[M],e[N],w[N],ne[N],idx=0;
int n,m,ss,ee;
void add(int a,int b,int c)
{
e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
int dij(int ss,int ee)
{
memset(dist,0x3f,sizeof dist);
// priority_queue<PII, vector<PII>, greater<PII> > heap;
priority_queue<PII, vector<PII>, greater<PII>> heap;
heap.push({0,ss});
dist[ss]=0;
while(heap.size())
{
auto t=heap.top();
heap.pop();
int ver=t.second;
if(st[ver])continue;
st[ver]=true;
for(int i=h[ver];i!=-1;i=ne[i])
{
int j=e[i];
if(dist[j]>dist[ver]+w[i])
{
dist[j]=dist[ver]+w[i];
heap.push({dist[j],j});
}
}
}
return dist[ee];
}
int main()
{
memset(h, -1, sizeof h);
cin>>n>>m>>ss>>ee;
int a,b,c;
while (m -- ){
cin>>a>>b>>c;
add(a,b,c);
add(b,a,c);
}
cout<<dij(ss,ee)<<endl;
}
2.信使----floyd
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 210;
int d[N][N];
int n,m;
int main()
{
int a,b,c;
cin>>n>>m;
memset(d,0x3f,sizeof d);
d[1][1]=0;
while (m -- ){
cin>>a>>b>>c;
d[a][b]=d[b][a]=min(d[a][b],c);
}
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
d[i][j]=min(d[i][k]+d[k][j],d[i][j]);
int res=0;
for(int i=2;i<=n;i++)
{
if(d[1][i]==0x3f3f3f3f)
{
cout<<"-1"<<endl;
return 0;
}
else res=max(res,d[1][i]);
}
cout<<res<<endl;
}
3.香甜的黄油----dijkstra
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
typedef pair<int, int> PII;
const int N = 3000;
int e[N],h[N],w[N],ne[N],idx=0;
int dist[N],id[N];
bool st[N];
int n,p,m;
void add(int a,int b,int c)
{
e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
int dij(int ss)
{
memset(st,0,sizeof st);
memset(dist,0x3f,sizeof dist);
priority_queue<PII,vector<PII>,greater<PII>>q;
q.push({0,ss});
dist[ss]=0;
while(q.size())
{
auto t=q.top();
q.pop();
int ver=t.second;
if(st[ver])continue;
st[ver]=true;
for(int i=h[ver];i!=-1;i=ne[i])
{
int j=e[i];
if(dist[j]>dist[ver]+w[i])
{
dist[j]=dist[ver]+w[i];
q.push({dist[j],j});
}
}
}
int res=0;
for(int i=1;i<=n;i++)
{
if(dist[id[i]]==0x3f3f3f3f)return 0x3f3f3f3f;
else
res+=dist[id[i]];
}
return res;
}
int main()
{
cin>>n>>p>>m;
memset(h,-1,sizeof h);
int x;
for(int i=1;i<=n;i++)
{
cin>>id[i];
}
int a,b,c;
while (m -- )
{
cin>>a>>b>>c;
add(a,b,c);
add(b,a,c);
}
int res=0x3f3f3f3f;
for(int i=1;i<=p;i++)
{
res=min(res,dij(i));
}
cout<<res<<endl;
}
4.最小花费----朴素版dijkstra
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 2010;
int n,m,ss,tt;
double g[N][N];
double dist[N];
bool st[N];
void dij()
{
dist[ss]=1;
for(int i=1;i<=n;i++)
{
int t=-1;
for(int j=1;j<=n;j++)
{
if(!st[j]&&(t==-1||dist[t]<dist[j]))
{
t=j;
}
}
st[t]=true;
for(int j=1;j<=n;j++)
{
dist[j]=max(dist[j],dist[t]*g[t][j]);
}
}
}
int main()
{
cin>>n>>m;
int a,b,c;
while (m -- )
{
cin>>a>>b>>c;
double t=(100.0-c)/100.0;
g[a][b]=g[b][a]=max(g[a][b],t);
}
cin>>ss>>tt;
dij();
printf("%.8lf\n",100/dist[tt]);
}
5.最优乘车----bfs+建图
#include <iostream>
#include <cstring>
#include <algorithm>
#include <sstream>
using namespace std;
const int N = 1000;
int g[N][N];
int n,m;
int dist[N],q[N];
int cnt=0;
int stop[N];
void bfs()
{
int hh=0,tt=-1;
memset(dist,0x3f,sizeof dist);
q[++tt]=1;
dist[1]=0;
while(hh<=tt)
{
auto t=q[hh++];
for(int i=1;i<=n;i++)
{
if(g[t][i]&&dist[i]==0x3f3f3f3f)
{
dist[i]=dist[t]+1;
q[++tt]=i;
}
}
}
}
int main()
{
cin>>m>>n;
string s;
getline(cin,s);
while (m -- )
{
getline(cin,s);
stringstream ssin(s);
int p,cnt=0;
while(ssin>>p)stop[cnt++]=p;
for(int i=0;i<cnt;i++)
for(int j=i+1;j<cnt;j++)
g[stop[i]][stop[j]]=true;
}
bfs();
if(dist[n]==0x3f3f3f3f)cout<<"NO"<<endl;
else cout<<max(dist[n]-1,0)<<endl;
}
6.昂贵的聘礼----朴素版dijkstra+有限制的建图方式+虚拟原点
题目链接
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 110,INF=0x3f3f3f3f;
int g[N][N];
int level[N];
int dist[N];
bool st[N];
int n,m;
int dij(int ss,int ee)
{
memset(st, 0, sizeof st);
memset(dist,0x3f,sizeof dist);
dist[0]=0;
for(int i=0;i<=n;i++)
{
int t=-1;
for(int j=0;j<=n;j++)
{
if(!st[j]&&(t==-1||dist[t]>dist[j]))
{
t=j;
}
}
st[t]=true;
for(int j=1;j<=n;j++)
{
if(level[j]>=ss&&level[j]<=ee)
{
dist[j]=min(dist[j],dist[t]+g[t][j]);
}
}
}
return dist[1];
}
int main()
{
cin>>m>>n;
memset(g,0x3f,sizeof g);
for(int i=1;i<=n;i++)g[i][i]=0;
for(int i=1;i<=n;i++)
{
int w,cnt;
cin>>w>>level[i]>>cnt;
g[0][i]=min(g[0][i],w);
while(cnt--)
{
int a,b;
cin>>a>>b;
g[a][i]=min(g[a][i],b);
}
}
int res=INF;
for(int i=level[1]-m;i<=level[1];i++)res=min(res,dij(i,i+m));
cout<<res<<endl;
}
7.新年好
算法:建图+堆优化dijkstra+dfs+暴力
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
typedef pair<int, int> PII;
const int N = 50010,M=200010;
const int INF = 0x3f3f3f3f;
int h[N],w[M],e[M],ne[M],idx=0;
bool st[N];
int dist[6][N];
int n,m;
int source[6];
void add(int a,int b,int c)
{
e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
void dij(int ss,int dist[])
{
memset(dist,0x3f,N*4);
memset(st, 0, sizeof st);
priority_queue<PII,vector<PII>,greater<PII> >q;
dist[ss]=0;
q.push({0,ss});
while(q.size())
{
auto t=q.top();
q.pop();
int ver=t.second;
if(st[ver])continue;
st[ver]=true;
for(int i=h[ver];i!=-1;i=ne[i])
{
int j=e[i];
if(dist[j]>dist[ver]+w[i])
{
dist[j]=dist[ver]+w[i];
q.push({dist[j],j});
}
}
}
}
int dfs(int u,int ss,int distance)
{
if(u>5)return distance;
int res=INF;
for(int i=1;i<=5;i++)
{
if(!st[i])
{
int next=source[i];
st[i]=true;
res=min(dfs(u+1,i,distance+dist[ss][next]),res);
st[i]=false;
}
}
return res;
}
int main()
{
memset(h,-1,sizeof h);
cin>>n>>m;
for(int i=1;i<6;i++)cin>>source[i];
source[0]=1;
while (m -- ){
int a,b,c;
cin>>a>>b>>c;
add(a,b,c);
add(b,a,c);
}
for(int i=0;i<6;i++)dij(source[i],dist[i]);
memset(st,0,sizeof st);
cout<<dfs(1,0,0)<<endl;
}
8.通信线路
最大值最小一般都可以二分来做
这题的难点在于对结果的限制条件k,求结果最大值最小,用二分,把大于答案的边长度设为1,小于答案的边为0,求0,1路径可用双端队列求解,是代码更加简练
链接
#include <iostream>
#include <cstring>
#include <algorithm>
#include <deque>
using namespace std;
const int N = 1010,M=20010;
int h[N],w[M],e[M],ne[M],idx=0;
int n,p,k;
int dist[N];
bool st[N];
void add(int a,int b,int c)
{
e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
bool check(int bound)
{
memset(st, 0, sizeof st);
memset(dist,0x3f,sizeof dist);
deque<int>q;
q.push_back(1);
dist[1]=0;
while(q.size())
{
int t=q.front();
q.pop_front();
for(int i=h[t];i!=-1;i=ne[i])
{
int j=e[i],x=w[i]>bound;
if(dist[j]>dist[t]+x)
{
dist[j]=dist[t]+x;
if(!x)q.push_front(j);
else q.push_back(j);
}
}
}
return dist[n]<=k;
}
int main()
{
memset(h,-1,sizeof h);
cin>>n>>p>>k;
int a,b,c;
while(p--)
{
cin>>a>>b>>c;
add(a,b,c);
add(b,a,c);
}
int l=0,r=1e6+1;
while(l<r)
{
int mid=l+r>>1;
if(check(mid))r=mid;
else l=mid+1;
}
if(r==1e6+1)cout<<-1<<endl;
else cout<<r<<endl;
}
9.道路与航线–dfs+topsort+dijkstra+建图方式
算法流程
1.先输入所有双向道路,然后DFS
出所有连通块,计算两个数组:id[]
存储每个点属于哪个连通块;vector<int> block[]
存储每个连通块里有哪些点:
2.输入所有航线,同时统计出每个连通块的入度。
3.按照拓扑序依次处理每个连通块,先将所有入度为0
的连通块的编号加入队列
中。
4.每次从队头取出一个连通块的编号bid
5.将该block[bid]
中的所有点加入堆中,然后对堆中所有点跑dijkstra
算法。
6.每次取出堆中距离最小的点ver
。
7.然后遍历ver
的所有邻点j
。如果id[ver]==id[]
,那么如果j能被更新,则将j
插入堆中:如果id[ver]!= id[j]
,则将id[j]
这个连通块的入度减1
,如果减成0
了,则将其插入拓扑排序的队列中
题目链接
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
#define x first
#define y second
const int N = 25010,M=150010;
int h[N],e[M],ne[M],w[M],idx=0;
int dist[N];
bool st[N];
vector<int>block[N];
int bcnt=0;
int id[N];
int n,rm,pm,s;
int din[N];
queue<int>q;
void add(int a,int b,int c)
{
e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
void dfs(int u,int bid)
{
id[u]=bid;
block[bid].push_back(u);
for(int i=h[u];i!=-1;i=ne[i])
{
int j=e[i];
if(!id[j])
{
dfs(j,bid);
}
}
}
void dij(int bid)
{
memset(st, 0, sizeof st);
priority_queue<PII,vector<PII>,greater<PII> >heap;
for(auto u:block[bid])
{
heap.push({dist[u],u});
}
while(heap.size())
{
auto t=heap.top();
heap.pop();
int ver=t.second;
if(st[ver])continue;
st[ver]=true;
for(int i=h[ver];i!=-1;i=ne[i])
{
int j=e[i];
if(id[j]!=id[ver]&&--din[id[j]]==0)q.push(id[j]);
if(dist[j]>dist[ver]+w[i])
{
dist[j]=dist[ver]+w[i];
if(id[j]==id[ver])heap.push({dist[j],j});
}
}
}
}
void topsort()
{
memset(dist,0x3f,sizeof dist);
dist[s]=0;
for(int i=1;i<=bcnt;i++)
{
if(din[i]==0)
{
q.push(i);
}
}
while(q.size())
{
int t=q.front();
q.pop();
dij(t);
}
}
int main()
{
memset(h,-1,sizeof h);
cin>>n>>rm>>pm>>s;
int a,b,c;
while(rm--)
{
cin>>a>>b>>c;
add(a,b,c);
add(b,a,c);
}
for(int i=1;i<=n;i++)
{
if(!id[i])
{
dfs(i,++bcnt);
}
}
while(pm--)
{
cin>>a>>b>>c;
din[id[b]]++;
add(a,b,c);
}
topsort();
for(int i=1;i<=n;i++)
{
if(dist[i]>0x3f3f3f3f/2)cout<<"NO PATH"<<endl;
else cout<<dist[i]<<endl;
}
}
10.最优贸易
题目链接
双spfa同时进行
先求出:
从 1
走到 i
的过程中,买入水晶球的最低价格 dmin[i]
;
从 i
走到 n
的过程中,卖出水晶球的最高价格 dmax[i]
;
然后枚举每个城市作为买卖的中间城市,求出 dmax[i] - dmin[i]
的最大值即可。
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 100010,M=2000010;
int h[N],rh[N],e[M],ne[M],idx=0;
int n,m;
int dist[N];
bool st[N];
int dmax[N],dmin[N];
void add(int h[],int a,int b)
{
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void spfa(int d[],int start,int h[],bool flag)
{
queue<int>q;
memset(st,0,sizeof st);
if(flag)memset(d,0x3f,sizeof dmin);
q.push(start);
d[start]=dist[start];
st[start]=true;
while(q.size())
{
int t=q.front();
q.pop();
st[t]=false;
for(int i=h[t];i!=-1;i=ne[i])
{
int j=e[i];
if(flag&&d[j]>min(d[t],dist[j])||!flag&&d[j]<max(d[t],dist[j]))
{
if(flag){
d[j]=min(d[t],dist[j]);
}
else d[j]=max(d[t],dist[j]);
if(!st[j])
{
st[j]=true;
q.push(j);
}
}
}
}
}
int main()
{
cin>>n>>m;
memset(h, -1, sizeof h);
memset(rh,-1,sizeof rh);
for(int i=1;i<=n;i++)cin>>dist[i];
while (m -- )
{
int a,b,c;
cin>>a>>b>>c;
add(h,a,b);
add(rh,b,a);
if(c==2)
{
add(h,b,a);
add(rh,a,b);
}
}
spfa(dmin,1,h,true);
spfa(dmax,n,rh,false);
int res=0;
for(int i=1;i<=n;i++)res=max(res,dmax[i]-dmin[i]);
cout<<res<<endl;
}
11.选择最佳线路
添加链接描述
稠密图,用邻接矩阵,建立超级原点。
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int n,m,s;
const int N = 1010;
int g[N][N];
bool st[N];
int dist[N];
void dij()
{
memset(st,0,sizeof st);
dist[0]=0;
for(int i=1;i<=n;i++)
{
int t=-1;
for(int j=0;j<=n;j++)
{
if(!st[j]&&(t==-1||dist[t]>dist[j]))
{
t=j;
}
}
st[t]=true;
for(int i=1;i<=n;i++)
{
dist[i]=min(dist[i],dist[t]+g[t][i]);
}
}
}
int main()
{
int a,b,c,x,cnt;
while(~scanf("%d%d%d",&n,&m,&s))
{
memset(g,0x3f,sizeof g);
memset(dist,0x3f,sizeof dist);
while (m -- )
{
cin>>a>>b>>c;
g[a][b]=min(g[a][b],c);
}
cin>>cnt;
for(int i=0;i<cnt;i++)
{
cin>>x;
g[0][x]=0;
}
dij();
if(dist[s]==0x3f3f3f3f)cout<<-1<<endl;
else cout<<dist[s]<<endl;
}
}
12.最短路计数
题目链接
这道题比较新奇,同时使用bfs时不需要设置st数组,类似于spfa的松弛操作
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 100010,M=400010;
const int mod = 100003;
int h[N],e[M],ne[M],idx=0;
int dist[N];
int n,m;
int cnt[N];
void add(int a,int b)
{
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void bfs()
{
memset(dist,0x3f,sizeof dist);
cnt[1]=1;
dist[1]=0;
queue<int>q;
q.push(1);
while(q.size())
{
int t=q.front();
q.pop();
for(int i=h[t];i!=-1;i=ne[i])
{
int j=e[i];
if(dist[j]>dist[t]+1)
{
dist[j]=dist[t]+1;
cnt[j]=cnt[t];
q.push(j);
}
else if(dist[j]==dist[t]+1)
{
cnt[j]=(cnt[j]+cnt[t])%mod;
}
}
}
}
int main()
{
cin>>n>>m;
memset(h,-1,sizeof h);
int a,b;
while (m -- ){
cin>>a>>b;
add(a,b);
add(b,a);
}
bfs();
for(int i=1;i<=n;i++)cout<<cnt[i]<<endl;
}
13.牛的旅行
多源汇最短路Floyd算法
题目链接
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define x first
#define y second
typedef pair<double, double> PDD;
const int N = 155;
PDD q[N];
const double INF = 1e20;
double d[N][N];
int n;
double maxd[N];
char g[N][N];
double get_dist(PDD a,PDD b)
{
double dx=a.x-b.x;
double dy=a.y-b.y;
return sqrt(dx*dx+dy*dy);
}
int main()
{
cin>>n;
for(int i=0;i<n;i++)
cin>>q[i].x>>q[i].y;
for(int i=0;i<n;i++)cin>>g[i];
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
{
if(i==j)d[i][j]=0;
else if(g[i][j]=='1')d[i][j]=get_dist(q[i],q[j]);
else d[i][j]=INF;
}
for(int k=0;k<n;k++)
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
d[i][j]=min(d[i][k]+d[k][j],d[i][j]);
double res1=0;
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
if(d[i][j]<INF/2)maxd[i]=max(maxd[i],d[i][j]);
res1=max(maxd[i],res1);
}
double res2=INF;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(d[i][j]>INF/2)
{
res2=min(res2,maxd[i]+maxd[j]+get_dist(q[i],q[j]));
}
printf("%.6lf",max(res1,res2));
}
14.排序
多源汇最短路Floyd算法
#include <iostream>
#include <cstring>
#include <algorithm>
#include<cstdio>
using namespace std;
const int N = 26;
int n,m;
bool g[N][N],d[N][N];
bool st[N];
void floyd(){
memcpy(d,g,sizeof d);
for(int k=0;k<n;k++)
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
d[i][j]|=d[i][k]&&d[k][j];
}
int check(){
for(int i=0;i<n;i++)
if(d[i][i])
return 2;
for(int i=0;i<n;i++)
for(int j=0;j<i;j++)
if(!d[i][j]&&!d[j][i])
return 0;
return 1;
}
char get_min(){
for(int i=0;i<n;i++)
if(!st[i]){
bool flag=true;
for(int j=0;j<n;j++)
if(!st[j]&&d[j][i]){
flag=false;
break;
}
if(flag){
st[i]=true;
return 'A'+i;
}
}
}
int main()
{
while(cin>>n>>m,n||m){
memset(g,0,sizeof g);
int type=0,t;
for(int i=1;i<=m;i++){
char str[5];
cin>>str;
int a=str[0]-'A',b=str[2]-'A';
if(!type){
g[a][b]=1;
floyd();
type=check();
if(type)t=i;
}
}
if(!type)puts("Sorted sequence cannot be determined.");
else if(type==2)printf("Inconsistency found after %d relations.\n", t);
else {
memset(st, 0, sizeof st);
printf("Sorted sequence determined after %d relations: ", t);
for(int i=0;i<n;i++)printf("%c",get_min());
printf(".\n");
}
}
}