最短路

一.dijkstra算法模板:

//dijkstra 
#include<stdio.h>
#include<string.h>
#include<algorithm> 
#define INF 0x3f3f3f
#define max 1000+10
using namespace std;
int visit[max],map[max][max],dist[max],time[max];
int n,m;
int start;
void dijkstra(int start)
{
    int i,j,next;
    int mindist;
    for(i=1;i<=n;i++)
    {
        visit[i]=0;
        dist[i]=map[start][i];
    }
    visit[start]=1;
    for(i=2;i<=n;i++)
    {
        next=i;
        mindist=INF;
        for(j=1;j<=n;j++)
        {
            if(!visit[j]&&mindist>dist[j])
            {
                mindist=dist[j];
                next=j;
            }
        }
        visit[next]=1;
        for(j=1;j<=n;j++)
        {
            if(!visit[j]&&dist[next]+map[next][j]<dist[j])
            dist[j]=dist[next]+map[next][j];
        }
    }
} 
int main()
{
    int i,j,x,y,c,road,end;
    while(scanf("%d%d%d",&n,&m,&start)!=EOF)
    {
        memset(time,INF,sizeof(time));
        for(i=1;i<=n;i++)
        {
            for(j=1;j<=n;j++)
            {
                if(i==j)
                map[i][j]=0;
                else
                map[i][j]=INF;
            }
        }
        while(m--)
        {
            scanf("%d%d%d",&x,&y,&c);
            if(map[y][x]>c)
            map[y][x]=c;
        }
        dijkstra(start);
        scanf("%d",&road);
        for(i=0;i<road;i++)
        {
            scanf("%d",&end);
            time[i]=dist[end];
        }
        sort(time,time+road);
        if(time[0]==INF)
        printf("-1\n");
        else
        printf("%d\n",time[0]);
    } 
    return 0;
}
二.题目模板

1.城市平乱

题目:已知有一个城市发生叛乱,有N个部队维护M个城市的治安。知道城市之间相互到达的时间,N个部队分布在任意N个城市,问一个城市暴乱后,最少需要多长时间有部队营救。

思路:运用dijkstra算法,把暴乱地点当做起点,求出到达每个位置的最短时间,然后再比较一下,所有最短的来。

代码:https://blog.csdn.net/chenzhenyu123456/article/details/43973471

2.find the safest road

题目:已知一个矩阵表示城市建的安全系数,一条从u 到 v 的通道P 的安全度为Safe(P) = s(e1)*s(e2)…*s(ek) e1,e2,ek是P 上的边,输出两个城市间最安全道路的安全系数。

思路:dijkstra算法的模板题,但是要注意 dist[j]=dist[next]*map[next][j];  ,然后全程double

代码:https://blog.csdn.net/chenzhenyu123456/article/details/44118045

3.最短路径+最小花费问题

题目:给你n个点,m条无向边,每条边都有长度d和花费p,给你起点s终点t,要求输出起点到终点的最短距离及其花费,如果最短距离有多条路线,则输出花费最少的。

思路:直接在dijkstra算法里改一下模板,当dist[next]+map[next][j]==dist[j]&&money[next]+cost[next][j]<money[j]  时,进行money[j]=money[next]+cost[next][j]; 操作。然后~

代码:https://blog.csdn.net/chenzhenyu123456/article/details/44247177

4.对于数据太大的,map无法存储,可以用链表形式

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const ll LL_INF = 0x3f3f3f3f3f3f3f3f;
const double PI = acos(-1);
const int MAXN = 200009;
int n, m, tot, head[MAXN];
bool vis[MAXN];
ll f[MAXN];
struct Edge
{
	int to, w, nex;
}edge[MAXN * 2];
void init()
{
	tot = 0;
	memset(head, -1, sizeof(head));
}
void addedge(int x, int y, int z)
{
	edge[tot] = {y, z, head[x]};
	head[x] = tot++;
}
void solve()
{
	memset(vis, 0, sizeof(vis));
	memset(f, LL_INF, sizeof(f));
	f[1] = 0;
	queue <int> q;
	q.push(1);
	vis[1] = 1;
	while (!q.empty()) {
		int u = q.front(); q.pop();
		vis[u] = 0;
		for (int i = head[u]; i != -1; i = edge[i].nex) 
        {
			int v = edge[i].to;
			if (f[u] + edge[i].w < f[v]) {
				f[v] = f[u] + edge[i].w;
				if (!vis[v]) {
					q.push(v);
					vis[v] = 1;
				}
			}
		}
	}
}
int main()
{
	while (~scanf("%d %d", &n, &m)) {
		init();
		for (int i = 1; i <= m; ++i) {
			int x, y, z;
			scanf("%d %d %d", &x, &y, &z);
			addedge(x, y, z);
			addedge(y, x, z);
		}
		solve();
		if (f[n] == LL_INF) puts("qwb baka");
		else printf("%lld\n", f[n]);
	}
	return 0;
}

5.最少换乘

题目大意:给定M条单向路径(由左到右按顺序给出),问最少换乘多少站使得能从1-n,不能的话输出-1

思路:将给定的单向边(所有)的权值赋为1(注意是任意两个距离为1),然后用dijkstra算法跑一遍再减一(多算了第一个线程,不计入总和)

坑点:输入的数据要按string类型进行处理。

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#define MAX 500+10
#define INF 0x3f3f3f
using namespace std;
char str[1200];
int m, n;
int map[MAX][MAX];
int dist[MAX];
int vis[MAX];
void init()//初始化 
{
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= n ;j++)
        {
            if(i == j)
            map[i][j] = 0;
            else
            map[i][j] = INF;
        }
    }
}
void getmap()//建图 
{
    int rec[MAX];
    int sum;
    int t;
    int i, j, k;
    for(i = 0; i < m; i++)
    {
        gets(str);
        t = 0;
        for(j = 0; j < strlen(str); j++)
        {
            if(str[j] != ' ')
            {
                sum = 0;
                while(str[j] != ' ' && j < strlen(str))
                {
                    sum = sum * 10 + (str[j]-'0');
                    ++j;
                }
                rec[t++] = sum;
            }
        }
        for(j = 0; j < t; j++)//每次更新 
        {
            for(k = j+1; k < t; k++)
            {
                map[rec[j]][rec[k]] = 1;
            }
        }
    }
}
void dijkstra()
{
    int i, j;
    int min, next;
    for(i = 1; i <= n; i++)
    {
        dist[i] = map[1][i];
        vis[i] = 0;
    }
    vis[1] = 1;
    for(i = 2; i <= n; i++)
    {
        min = INF;
        for(j = 1; j <= n; j++)
        {
            if(!vis[j] && min > dist[j])
            {
                next = j;
                min = dist[j];
            }
        }
        vis[next] = 1;
        for(j = 1; j <= n; j++)
        {
            if(!vis[j] && map[next][j] + dist[next] < dist[j])
            {
                dist[j] = dist[next] + map[next][j];
            }
        }
    }
    if(dist[n] == INF)
    printf("NO\n");
    else
    printf("%d\n", dist[n]-1);
}
int main()
{
    int t;
    scanf("%d", &t);
    while(t--)
    {
        scanf("%d%d", &m, &n);
        getchar();
        init();//初始化 
        getmap();//建图 
        dijkstra();//求最短路 
    }
    return 0;
} 

6.frogger—两点最大距离的最小值

题目大意:给定n个点的坐标,求第1个和第二个点的所有路径中两点间的最大值

思路:利用floyd,d[i][j]=min(d[i][j],max(d[i][k],d[k][j]));就是找其中最大值的最小值保存起来。

具体见代码:

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=205;
double d[N][N];
int x[N],y[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],max(d[i][k],d[k][j]));
}

int main()
{
    int cas=0;
    while(scanf("%d",&n),n)
    {
        memset(d,0x3f,sizeof(d));
        for(int i=1;i<=n;++i)
        {
            scanf("%d%d",&x[i],&y[i]);
            for(int j=1;j<i;++j)
            {
                int tx=x[i]-x[j],ty=y[i]-y[j];
                d[i][j]=d[j][i]=sqrt(tx*tx+ty*ty);
            }
        }
        floyd();
        printf("Scenario #%d\nFrog Distance = %.3f\n\n",++cas,d[1][2]);
    }
    return 0;
}

7.find the mincost route(考察对floyd算法的理解)

题目大意:杭州有N个景区,景区之间有一些双向的路来连接,现在8600想找一条旅游路线,这个路线从A点出发并且最后回到A点,假设经过的路线为V1,V2,....VK,V1,那么必须满足K>2,就是说至除了出发点以外至少要经过2个其他不同的景区,而且不能重复经过同一个景区。现在8600需要你帮他找一条这样的路线,并且花费越少越好。

思路:考虑到floyd算法在循环中,穷举每个点k作为中间节点来更新其他点a,b之间的距离,而当某个点k未被枚举到时,是不会有一条路径包含在中间的,他顶多可以作为路径的起点或者终点。利用这点,在未枚举到的k作为某中间点时,可以枚举一下与k相连的两条边,即i->k->j



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值