目录
2. 单源最短路径 Dijkstra算法(非负)(链式向前星+优先队列 优化)
3. SPFA算法(可负)(Shortest Path Fast Algorithm)
4. EX: POJ-3662-Telephone Lines
6. EX BZOJ2200 [Usaco2011 Jan] 道路和航线
8. EX POJ1094 Sorting It All Out
9. EX POJ1734 Sightseeing trip
链式向前星的空间复杂度:O(n+m)
- const int N=100010;//点
- const int M=1000010;//边
- int head[N],ver[M],edge[M],Next[M],d[N];//头节点,边的尾点,权值,指向的上一条边,点N到起点的距离
- int n,m,tot;
-
- //加入有向边(x,y),权值为z
- void add(int x,int y,int z){
- ver[++tot]=y,edge[tot]=z; // 真实数据
- Next[tot]=head[x],head[x]=tot; //从表头x处插入
- }
-
- //初始化
- void init(){
- tot=0;
- memset(head,0,sizeof head);
- }
-
- //访问从x出发的所有边
- for(int i=head[x];i;i=Next[i]){
- int y=ver[i],z=edge[i];
- // 找到了一条有向边(x,y),权值为z
- }
- //dijkstra单源最短路径:链式向前星+优先队列 O((m+n)logn)
- #include
- using namespace std;
- const int N=100010;
- const int M=1000010;
- const int INF=0x3f3f3f3f;
- int head[N],ver[M],edge[M],Next[M],d[N];//头节点,边的尾点,权值,指向的上一条边,点N到起点的距离
- bool v[N];
- int n,m,tot;
- priority_queue
int,int> > pq;//大根堆,pair第二维为节点编号,第一维为dist的相反数(利用相反数变成小根堆) - void add(int x,int y,int z){
- ver[++tot]=y,edge[tot]=z,Next[tot]=head[x],head[x]=tot;
- }
- void init(){
- tot=0;
- memset(head,0,sizeof head);
- }
- void dijkstra(){
- int s=1; // 起点
- memset(d,0x3f,sizeof d); //dist数组
- memset(v,0,sizeof v); //节点标记
- d[s]=0;
- pq.push(make_pair(-d[s],s)); //起点入队
- while(pq.size()){
- int x=pq.top().second; pq.pop(); //取出堆顶
- if(v[x]) continue; //已经找到最短路
- v[x]=1;
- //扫描所有边
- for(int i=head[x];i;i=Next[i]){
- int y=ver[i],z=edge[i];
- if(d[y]>d[x]+z){
- //更新,把新的二元组插入堆
- d[y]=d[x]+z;
- pq.push(make_pair(-d[y],y));
- }
- }
- }
- }
- int main(){
- while(cin>>n>>m&&n&&m){
- init();
- for(int i=1;i<=m;i++){
- int x,y,z;
- cin>>x>>y>>z;
- add(x,y,z);
- add(y,x,z);
- }
- dijkstra();
- cout<
- }
- return 0;
- }
3. SPFA算法(可负)(Shortest Path Fast Algorithm)
- #include
- using namespace std;
- const int INF=INT_MAX/10;
- const int N=100010;
- const int M=1000010;
- int head[N],ver[M],edge[M],Next[M],d[N];//头节点,边的尾点,权值,指向的上一条边,点N到起点的距离
- int Neg[M]; //判断负圈
- int pre[N]; //记录前驱节点
- bool inq[N]; //inq[i]=true表示节点i在队列中
- int n,m,tot;
- void print_path(int s,int t){ //打印从s到t的最短路径
- if(s==t){cout<
return;} //打印起点 - print_path(s,pre[t]); //先打印前一个点
- cout<
//后打印当前点,最后打印的是终点t - }
- void init(){
- tot=0;
- memset(head,0,sizeof head);
- }
- void add(int x,int y,int z){
- ver[++tot]=y,edge[tot]=z,Next[tot]=head[x],head[x]=tot;
- }
- int spfa(int s){//s是起点
- memset(Neg,0,sizeof Neg);
- Neg[s]=1;
- for(int i=1;i<=n;i++){d[i]=INF,inq[i]=false;} //初始化
- d[s]=0; //起点到自己距离为0
- queue<int> q;
- q.push(s);
- inq[s]=true; //起点进入队列
- while(q.size()){
- int u=q.front(); q.pop(); //队头出队
- inq[u]=false;
- for(int i=head[u];i;i=Next[i]){
- int v=ver[i],w=edge[i];
- if(d[v]>d[u]+w){ //u的第i个邻居v,它借道u,到s更近
- d[v]=d[u]+w; //更新第i个邻居到s的距离
- pre[v]=u;
- if(!inq[v]){//邻居v更新状态了,但是它不在队列中,把它放进队列
- inq[v]=true;
- q.push(v);
- Neg[v]++;
- if(Neg[v]>n) return 1; //出现负圈
- }
- }
- }
- }
- cout<
//从s到n的最短距离 - //print_path(s,n);
- return 0;
- }
- int main(){
- while(cin>>n>>m&&n&&m){
- init();
- while(m--){
- int u,v,w;
- cin>>u>>v>>w;
- add(u,v,w);
- add(v,u,w);
- }
- spfa(1);
- }
- return 0;
- }
4. EX: POJ-3662-Telephone Lines

做法一:分层图最短路
- #include
- #include
- #include
- #include
- using namespace std;
- int n, p, k, vis[1010][1010], d[1010][1010];
- typedef pair<int,int> P;
- struct Nod {
- int v, c, w;
- bool operator < (const Nod &a) const {
- return w > a.w;
- }
- };
- vector
G[1010];
- void spfa(int s) {
- memset(d,-1,sizeof(d));memset(vis,0,sizeof(vis));
- d[s][0] = 0;
- priority_queue
que; - que.push((Nod){s,0,0});
- while(!que.empty()) {
- int u = que.top().v, c = que.top().c; que.pop();
- if(vis[u][c])continue;
- vis[u][c] = 1;
- for(int i = 0; i < G[u].size(); i ++) {
- int v = G[u][i].first, w = G[u][i].second;
- if(!vis[v][c] && (d[v][c] == -1 || d[v][c] > max(d[u][c],w))) {
- d[v][c] = max(d[u][c], w);
- que.push((Nod){v,c,d[v][c]});
- }
- if(c < k) {
- if(!vis[v][c+1] && (d[v][c+1] == -1 || d[v][c+1] > d[u][c])) {
- d[v][c+1] = d[u][c];
- que.push((Nod){v,c+1,d[v][c+1]});
- }
- }
- }
- }
- }
- int main() {
- ios::sync_with_stdio(false);
- cin>>n>>p>>k;
- int s = 1, t = n;
- for(int i = 1; i <= p; i ++) {
- int u, v, w;
- cin>>u>>v>>w;
- G[u].push_back(P(v,w));
- G[v].push_back(P(u,w));
- }
- spfa(s);
- int ans = 10000010;
- for(int i = 0; i <= k; i ++) ans = min(ans,d[t][i]);
- printf("%d\n",ans);
- return 0;
- }
做法二:二分答案+双端队列BFS
对于边权只有0和1的最短路问题,可以使用双端队列BFS求解,复杂度
。
- #include
- #include
- #include
- #include
- #include
- using namespace std;
- #define maxv 1005
- struct edge
- {
- int v, w;
- edge(int a=0,int b=0){v=a,w=b;}
- };
- int V, E, K, d[maxv];
- bool used[maxv];
- vector
G[maxv]; -
- int bfs(int m)
- {
- memset(d, 0x3f, sizeof(d));
- memset(used, 0, sizeof(used));
- deque<int> q;
- d[1] = 0;
- q.push_back(1);
- while (!q.empty())
- {
- int u = q.front();
- q.pop_front();
- if (used[u])
- continue;
- used[u] = 1;
- for (int i = 0; i < (int)G[u].size(); ++i)
- {
- edge &e = G[u][i];
- if (e.w > m)
- {
- if (d[e.v] > d[u] + 1)
- d[e.v] = d[u] + 1, q.push_back(e.v);
- }
- else
- {
- if (d[e.v] > d[u])
- d[e.v] = d[u], q.push_front(e.v);
- }
- }
- }
- return d[V];
- }
-
- int main()
- {
- scanf("%d%d%d", &V, &E, &K);
- int maxl = 0;
- for (int i = 0; i < E; ++i)
- {
- int u, v, w;
- scanf("%d%d%d", &u, &v, &w);
- maxl = max(maxl, w);
- G[v].push_back(edge(u, w));
- G[u].push_back(edge(v, w));
- }
- if (bfs(maxl))
- {
- puts("-1");
- return 0;
- }
- int lb = -1, ub = maxl;
- while (ub - lb > 1)
- {
- int mid = (lb + ub) >> 1;
- if (bfs(mid) <= K)
- ub = mid;
- else
- lb = mid;
- }
- printf("%d\n", ub);
- return 0;
- }
做法三:二分答案+dijkstra
对于二分的判定,dijkstra求最短路,复杂度
。
5. EX CH6101 / P1073 最优贸易
- #include
- using namespace std;
- const int N = 1e5 + 6, M = 1e6 + 6;
- int n, m, tot, Price[N], Ans;
- int Head[N], Side[M], Next[M], ans[N];
- int fHead[N], fSide[M], fNext[M], fans[N];
- priority_queue
int, int> > q; - priority_queue
int, int> > fq; -
- int main() {
- cin >> n >> m;
- for (int i = 1; i <= n; i++) scanf("%d", &Price[i]);
- for (int i = 1; i <= m; i++) {
- int x, y, z;
- scanf("%d %d %d", &x, &y, &z);
- Side[++tot] = y;
- Next[tot] = Head[x];
- Head[x] = tot;
- fSide[tot] = x;
- fNext[tot] = fHead[y];
- fHead[y] = tot;
- if (z == 2) {
- Side[++tot] = x;
- Next[tot] = Head[y];
- Head[y] = tot;
- fSide[tot] = y;
- fNext[tot] = fHead[x];
- fHead[x] = tot;
- }
- }
- memset(ans, 0x3f, sizeof(ans));
- memset(fans, 0xcf, sizeof(fans));
- ans[1] = Price[1];
- fans[n] = Price[n];
- q.push(make_pair(-ans[1], 1));
- fq.push(make_pair(fans[n], n));
- while (q.size()) {
- int x = q.top().second;
- q.pop();
- for (int i = Head[x]; i; i = Next[i]) {
- int y = Side[i];
- if (ans[y] > ans[x]) {
- ans[y] = ans[x];
- ans[y] = min(ans[y], Price[y]);
- q.push(make_pair(-ans[y], y));
- }
- }
- }
- while (fq.size()) {
- int x = fq.top().second;
- fq.pop();
- for (int i = fHead[x]; i; i = fNext[i]) {
- int y = fSide[i];
- if (fans[y] < fans[x]) {
- fans[y] = fans[x];
- fans[y] = max(fans[y], Price[y]);
- fq.push(make_pair(fans[y], y));
- }
- }
- }
- for (int i = 1; i <= n; i++) Ans = max(Ans, fans[i]-ans[i]);
- cout << Ans << endl;
- return 0;
- }
6. EX BZOJ2200 [Usaco2011 Jan] 道路和航线
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- using namespace std;
- typedef long long ll;
- const int N=3e5+10,M=3e5+10;
- const int INF=0x7f7f7f7f;
- inline int read()
- {
- int x=0,f=1; char ch=getchar();
- while(ch<'0' || ch>'9'){if(ch=='-')f=-1; ch=getchar();}
- while(ch>='0' && ch<='9'){x=x*10+ch-'0'; ch=getchar();}
- return x*f;
- }
- struct edge
- {
- int x,y,c,next;
- }a[N]; int len,last[N];
- void ins(int x,int y,int c)
- {
- a[++len].x=x;a[len].y=y;a[len].c=c;
- a[len].next=last[x];last[x]=len;
- }
-
- bool v[N];
- int cnt;
- vector<int> has[N];
- int bl[N];
- void dfs(int x)
- {
- v[x]=1;
- has[cnt].push_back(x);
- for(int k=last[x];k;k=a[k].next)
- {
- int y=a[k].y;
- if(!v[y])bl[y]=bl[x],dfs(y);
- }
- }
-
- struct node
- {
- int d,id;
- bool operator <(const node &b) const
- {
- return d>b.d;
- }
- };
-
- priority_queue
int,int> > q; - int deg[N];
- int n,R,P,st;
- int list[M],head,tail;
- int dis[N];
- int main()
- {
- // freopen("a.in","r",stdin);
- // freopen("a.out","w",stdout);
- n=read(); R=read(); P=read(); st=read();
- len=0; memset(last,0,sizeof(last));
- for(int i=1;i<=R;i++)
- {
- int x=read(),y=read(),c=read();
- ins(x,y,c);
- ins(y,x,c);
- }
- //get scc
- cnt=0; memset(bl,0,sizeof(bl));
- memset(v,0,sizeof(v));
- for(int i=1;i<=n;i++)
- if(!v[i])
- {
- cnt++; bl[i]=cnt;
- dfs(i);
- }
- //rebuild to DAG
- memset(deg,0,sizeof(deg));
- for(int i=1;i<=P;i++)
- {
- int x=read(),y=read(),c=read();
- ins(x,y,c); ins(bl[x]+n,bl[y]+n,c);
- }
- //Get deg
- head=1,tail=1;
- list[1]=bl[st]+n;
- memset(v,0,sizeof(v));
- while(head<=tail)
- {
- int x=list[head];
- for(int k=last[x];k;k=a[k].next)
- {
- int y=a[k].y;
- if(!v[y])v[y]=1,list[++tail]=y;
- deg[y-n]++;
- }
- head++;
- }
- //Dij+Topsort
- memset(dis,0x7f,sizeof(dis)); dis[st]=0;
- memset(v,0,sizeof(v));
- head=1,tail=1;
- list[1]=bl[st];
- while(head<=tail)
- {
- int cc=list[head];
- // for(int i=1;i<=n;i++)if(bl[i]==cc)q.push(make_pair(-dis[i],i));
- int siz=has[cc].size();
- for(int i=0;i
push(make_pair(-dis[has[cc][i]],has[cc][i])); - while(q.size())
- {
- int x=q.top().second;q.pop();
- if(v[x])continue;
- v[x]=1;
- for(int k=last[x];k;k=a[k].next)
- {
- int y=a[k].y;
- if(bl[x]!=bl[y]){deg[bl[y]]--;
- if(deg[bl[y]]==0)list[++tail]=bl[y];}
- if(dis[y]>dis[x]+a[k].c)
- {
- dis[y]=dis[x]+a[k].c;
- if(bl[x]==bl[y])q.push(make_pair(-dis[y],y));
- }
- }
- }
-
- head++;
- }
-
- for(int i=1;i<=n;i++)
- {
- if(dis[i]==INF) puts("NO PATH");
- else printf("%d\n",dis[i]);
- }
- return 0;
- }
7. 任意两点间最短路径
Floyd算法 
- #include
- using namespace std;
- const int MAXN=105;
- const int INF=0x3f3f3f3f;
- int graph[MAXN][MAXN];//邻接矩阵存图
- int n,m;//n个点,m个边
- void floyd(){
- int s=1; //定义起点
- for(int k=1;k<=n;k++)
- for(int i=1;i<=n;i++)
- if(graph[i][k]!=INF)
- for(int j=1;j<=n;j++)
- if(graph[i][j]>graph[i][k]+graph[k][j])
- graph[i][j]=graph[i][k]+graph[k][j];
- cout<
- }
- int main(){
- while(~scanf("%d%d",&n,&m)&&n&&m){
- for(int i=1;i<=n;i++)
- for(int j=1;j<=n;j++)
- graph[i][j]=INF;//任意两点间初始距离为无穷大
- while(m--){
- int a,b,c;
- cin>>a>>b>>c;
- graph[a][b]=graph[b][a]=c;//邻接矩阵存图
- }
- floyd();
- }
- return 0;
- }
传递闭包
- //传递闭包 floyd算法
- #include
- using namespace std;
- const int MAXN=105;
- const int INF=0x3f3f3f3f;
- int graph[MAXN][MAXN];//邻接矩阵存图
- int n,m;//n个点,m个边
- void floyd(){
- int s=1; //定义起点
- for(int k=1;k<=n;k++)
- for(int i=1;i<=n;i++)
- if(graph[i][k]!=INF)
- for(int j=1;j<=n;j++)
- graph[i][j] |= graph[i][k] & graph[k][j];
- cout<
- }
- int main(){
- while(~scanf("%d%d",&n,&m)&&n&&m){
- for(int i=1;i<=n;i++)
- for(int j=1;j<=n;j++)
- graph[i][j]=INF;//任意两点间初始距离为无穷大
- while(m--){
- int a,b,c;
- cin>>a>>b>>c;
- graph[a][b]=graph[b][a]=c;//邻接矩阵存图
- }
- floyd();
- }
- return 0;
- }
8. EX POJ1094 Sorting It All Out
9. EX POJ1734 Sightseeing trip
10. POJ3613 EX Cow Relays
-
相关阅读:
手机自动直播系统源码交付与代理加盟注意事项解析!
学习Python低手之路【三】python基础之函数
折半查找的判定树
专注于绘画,不受限制!尝试Growly Draw for Mac的快速绘画应用
两个对象相等(==、equals、hashCode)详解
Docker安装Jenkins
计算机网络 第一章计算机网络体系结构
想知道怎样p漫画脸??用这两个方法,分分钟出片
流媒体服务器
【小题练手】----平方矩阵
-
原文地址:https://blog.csdn.net/qq_57351574/article/details/125878388