zoukankan      html  css  js  c++  java
  • PAT

    Nothing to fear


    种一棵树最好的时间是十年前,其次是现在!

    那些你早出晚归付出的刻苦努力,你不想训练,当你觉的太累了但还是要咬牙坚持的时候,那就是在追逐梦想,不要在意终点有什么,要享受路途的过程,或许你不能成就梦想,但一定会有更伟大的事情随之而来。 mamba out~

    2020.7.14


    人一我十,人十我百,追逐青春的梦想,怀着自信的心,永不言弃!

    Public Bike Management

    考点: Dijkstra求最短路,Dijkstra记录最短路径,dfs,阅读理解

    题目大意

    给定一个起点PBMC,和一个终点SP,求出从PBMC 到 Sp的最短路径(如果不止一条则都要记录下来),从中挑选出一条,从PBMC需要发送的车辆最少的那一条路径,如果遇到重复则输出需要将自行车返回回去的尽可能少的那一条(题目确保该路径唯一)。

    分析

    1.如何记录在Dijkstra中所求得得最短路径,由于Dijkstra时基于贪心思想当你要利用某一个顶点 x 去松弛其他顶点时,x之前得结点已经被确定,换句话说就是每当你确定一个点,这个点得前一个点一定已经被确定,虽然听起来像废话但是还是需要去好好考虑的!故我们可以用一个容器来存在某个点的前一个点来记录路径

    定义一个容器vector<int> pre[N]; 用于存放结点的所确定的前一个结点有哪些
    while(!q.empty())
    {
        int x = q.top().second;q.pop();
        if(vis[x])continue;
        vis[x] = 1;
        for(int i = 1;i <= n;i ++)
        {
            int y = i , w = e[x][i];
            if(dis[y] > dis[x] + w) // 更新 x -> y
            {
                pre[y].clear();
                pre[y].push_back(x);
                dis[y] = dis[x] + w;
                q.push({-dis[y] , y});
            }else if(dis[y] == dis[x] + w){
                pre[y].push_back(x);
            }
        }
    }
    

    2.得到路径之后需要对路径进行dfs检查所需要发送/放回都达到最优的那一条路!

    需要注意的点:

    • 认真读题
    • 如何记录Dijkstra的最短路径的结点需要熟记利用记录前一个结点的pre容器!

    完整代码

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <queue>
    using namespace std;
    const int N = 1005;
    int Cmax , n , m , sp , mid , minsent = 0x3f, mintake = 0x3f;
    int e[N][N] , dis[N] , carry[N];
    bool vis[N];
    priority_queue<pair<int,int> > q;
    vector<int> pre[N] , path;
    void dfs(vector<int> tmp, int now)
    {
    	if(now == 0)
    	{
    		int need = 0 , back = 0;
    		for(int i = tmp.size() - 1;i >= 0;i --)
    		{
    			int id = tmp[i];
    			if(carry[id] > 0)
    				back += carry[id];
    			else{
    				if(back > (0 - carry[id]))
    					back += carry[id];
    				else{
    					need += (0 - carry[id] - back);
    					back = 0;
    				}
    			}
    		}
    		if(need < minsent){
    			minsent = need;
    			mintake = back;
    			path = tmp;
    		}
    		if(need == minsent && back < mintake)
    		{
    			mintake = back;
    			path = tmp;
    		}
    	}
    	for(int i = 0;i < pre[now].size();i ++)
    	{
    		tmp.push_back(now);
    		dfs(tmp, pre[now][i]);
    		tmp.pop_back();
    	}
    }
    void Dijkstra()
    {
    	memset(dis , 0x3f , sizeof dis);
    	memset(vis , 0 ,sizeof vis);
    	dis[0] = 0; // 规定PBMC 为顶点 0
    	q.push({0 , 0});
    	while(!q.empty())
    	{
    		int x = q.top().second;q.pop();
    		if(vis[x])continue;
    		vis[x] = 1;
    		for(int i = 1;i <= n;i ++)
    		{
    			int y = i , w = e[x][i];
    			if(dis[y] > dis[x] + w) // 更新 x -> y
    			{
    				pre[y].clear();
    				pre[y].push_back(x);
    				dis[y] = dis[x] + w;
    				q.push({-dis[y] , y});
    			}else if(dis[y] == dis[x] + w){
    				pre[y].push_back(x);
    			}
    		}
    	}
    	vector<int> t;dfs(t, sp);
    }
    int main()
    {
    	memset(e , 0x3f , sizeof e);
    	for(int i = 0;i <= n;i ++)e[i][i] = 0;
    	cin >> Cmax >> n >> sp >> m;
    	mid = Cmax / 2;
    	for(int i = 1;i <= n;i ++)
    		scanf("%d",&carry[i]) , carry[i] = carry[i] - mid;
    	int a, b ,c;
    	for(int i = 0;i < m;i ++)
    	{
    		scanf("%d %d %d", &a ,& b, &c);
    		e[a][b] = e[b][a] = c;
    	}
    	Dijkstra();
    	cout << minsent << " 0";
    	for(int i = path.size() - 1;i >= 0;i --)
    	{
    		printf("->%d", path[i]);
    	}
    	cout << " " << mintake << endl;
    	return 0;
    }
    
  • 相关阅读:
    数据库备份与还原
    启明星产品与微软Active Directory活动目录集成说明
    启明星请假系统里,计算工作日的实现
    启明星会议室预定系统Outlook版开始支持Exchange2013与Office365版
    Jquery Mobile实例--利用优酷JSON接口读取视频数据
    高性能且线程安全的两种格式化日期方式
    将数列唯一值化后再求中值的效率比较 第一方案胜出,加索引后在近两百万数据中查出中值耗时0.176秒
    Oracle WITH 语句 语法
    新三种求数列中值SQL之效率再比拼
    rank,dense_rank和row_number函数区别
  • 原文地址:https://www.cnblogs.com/wlw-x/p/13299200.html
Copyright © 2011-2022 走看看