小峰峰的pat甲级刷题记录1030

很经典的最优路线问题

方法一:dfs

思路:

1.vector数组记录邻居关系用于深搜遍历
2.遍历过程中优化mindis_to[ ] ,fee[ ]
3.遍历过程中记录当前路径path
4.到达终点时优化最终答案

#include<iostream>
#include<vector>
using namespace std;


int N,M,S,D;
vector<int>v[500];
vector<int>path;
vector<int>final_path;
int final_dis=100000000,final_fee;
int dis[500][500];
int fee[500][500];
int mindis_to[500];

void dfs(int curnode,int curdis,int curfee)
{
    if(curdis>mindis_to[curnode])return;//深搜第一步,不走冤枉路
    path.emplace_back(curnode);
    if(curnode==D)
    {
        if(curdis<final_dis||(curdis==final_dis&&curfee<final_fee))
        {
            final_dis=curdis;
            final_path=path;
            final_fee=curfee;
        }
     
    }
    else
    {
        if(curdis<mindis_to[curnode])mindis_to[curnode]=curdis;
        for(int i:v[curnode])dfs(i,curdis+dis[i][curnode],curfee+fee[i][curnode]);
            
    }
    path.pop_back();
}

int main()
{
    int i,j,k,f;
    cin>>N>>M>>S>>D;
    while(M--)
    {
        cin>>i>>j>>k>>f;
        v[i].emplace_back(j);
        v[j].emplace_back(i);
        dis[i][j]=dis[j][i]=k;
        fee[i][j]=fee[j][i]=f;
    }
    for(i=0;i<N;i++)mindis_to[i]=100000000;
    dfs(S,0,0);
    for(int i:final_path)cout<<i<<' ';
    cout<<final_dis<<' '<<final_fee;
}

优化mindis_to[ ]的作用

1.首先,可以防止走回头路导致的段错误。这一功能也可以dfs多携带一个参数记录上一个经过的结点,下次不走来实现。

...
...
void dfs(...int pre)
{
	...
	...
	for(int i:v[curnode])
	{
		if(i!=pre)dfs(...,curnode); //第一次调用时pre=-1	
	}
 }
  1. 核心功能:剪枝,不走冤枉路

深搜遍历邻接表中“优化mindis_to[ ]”和 “使用vis[ ]标记走过点,只走未走过点的”的比较

  1. 二者都可以防止走回头路
  2. vis[]标记法保证每个结点都访问且只访问一次,但对任意节点只有一条路径。
    mindis_to[ ]法走且仅走每一条必须“探索”的路,这些“探索”用于优化到每一结点的最短路径。
  3. 遍历树时,mindis_to[ ]法没有意义,因为每个结点都只有一个前驱。vis[ ]法效果等同于pre法

方法二:dijkstra

dijkstra : 以最小步伐探索黑暗

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int MAXV = 510;
const int INF = 1000000000;

int n,m,st,ed;
int G[MAXV][MAXV],cost[MAXV][MAXV];
int mindis_to[MAXV],mincost_to[MAXV];
int pre[MAXV];
bool vis[MAXV]={false};


void dijkstra(int s)
{
    fill(mindis_to,mindis_to+MAXV,INF);
    fill(mincost_to,mincost_to+MAXV,INF);
    for(int i=0;i<n;i++)pre[i]=i; 
    mindis_to[s]=0;
    mincost_to[s]=0;
    for(int i=0;i<n;i++)
    {
        int u=-1,MIN = INF; // 寻找已探明且还未标记的最近点,记录它的序号和距离
        for(int j = 0;j<n;j++)
        {
            if(vis[j] == false && mindis_to[j] < MIN)
            {
                u = j;
                MIN = mindis_to[j];
            }
        }
        
        if(u==-1)return; // 无点可标,完成任务
        vis[u] = true; // 标记u
        for(int v=0;v<n;v++) // 以u为中转站,试图更新mindis_to[v]
        {
            if(vis[v] == false && G[u][v] != INF) // v未访问且u可直接到达v
            {
                if(mindis_to[u] + G[u][v] < mindis_to[v] || (mindis_to[u]+G[u][v]==mindis_to[v] && mincost_to[v] > mincost_to[u] + cost[u][v]))
                {
                    mindis_to[v] = mindis_to[u] + G[u][v];
                    mincost_to[v] = mincost_to[u] + cost[u][v];
                    pre[v] = u; // 记录前驱
                }
            }
        
        }
    }
}

void dfs(int v) // 打印路径
{
    if(v == st)
    {
        cout<<v<<' ';
        return;
    }
    dfs(pre[v]);
    cout<<v<<' ';
}

int main()
{
    int i,j,k,f;
    cin>>n>>m>>st>>ed;
    fill(G[0],G[0]+MAXV*MAXV,INF); // 初始化G
    while(m--)
    {
        cin>>i>>j>>k>>f;
        G[i][j]=G[j][i]=k;
        cost[i][j]=cost[j][i]=f;
    }
    dijkstra(st);
    dfs(ed);
    cout<<mindis_to[ed]<<' '<<mincost_to[ed];
}            
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值