UVA 1599 Ideal Path 【两次BFS+贪心】 (好题)

8 篇文章 0 订阅
7 篇文章 0 订阅

题目链接

题意

迷宫中有n个房间,m条路,每条路上都涂上了颜色(用整数表示),求按走的路径的颜色排列的字典序最小的最短路

分析

贪心方法

求最短路当然简单,每条路的长度都是1,BFS、SPFA、Dijkstra随便上都行。关键是求字典序最小的路径。根据字典序的特征贪心,从1到n,优先取所有可取最短路中颜色值最小的那条路。
但关键在于如何判断某条路是不是最短路上的路径,想到最短路问题通常打印路径的方法:

求最短路时总会求出每个点到起点的距离,那么为了判断某条路是否是最短路上的,逆向求一遍最短路(把想要的终点当做起点),求出每个点到终点的距离。那么如果一条路是最短路上的,则路的末端到终点的距离加上这条路的距离应当等于其起点到终点的距离。
逆向求是为了保证这条路总是会通向终点

那么这个题就可以先求出终点到各个点的距离,然后再从起点BFS,优先选择可选路径中颜色编号最小的路径。

判重以及最优的判断

Two rooms can be connected with more than one passage, there can be a passage from a room to itself.

题中说会有重边,若不对其进行处理,在第二次BFS中运行时间将成指数级增长。
+ 如果入队的指标本身就是BFS的层数,则不需要处理,因为BFS队列中层数小的必然会排在前面,不用担心后面会有更优的情况,因此若层数相同,则没必要入队。(如本题的第一次BFS,其中入队的判断dist[G[p][i].to]>dist[p]+1直接用大于即可,重边必不会入队)
+ 如果入队的指标与入队顺序无关(与层数无关或者说与点本身无关)则可能最优解不是队首或者队首在当前情况下看似是最优解但后面仍需判断,则入队指标相同也应当入队,并且入队更新出队还有再判断一次。(如本题第二次BFS中idealpath[p.steps+1]>=G[p.pos][i].color以及p.color>idealpath[p.steps]

可以看出在上述第二种情况下,重边的终点会被反复入队,而它们都会被视为最优解继续BFS下去,自然会TLE。这时一个visit数组即可解决
if(p.color>idealpath[p.steps]||visit[p.pos])

AC代码

(交c++,g++会T)

//UVA 1599 Ideal Path
//AC 2016-7-24 22:15:17
//BFS,Greedy
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cctype>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <set>
#include <string>
#include <map>
#include <queue>
#include <deque>
#include <list>
#include <sstream>
#include <stack>
using namespace std;

#define cls(x) memset(x,0,sizeof x)
#define inf(x) memset(x,0x3f,sizeof x)
#define neg(x) memset(x,-1,sizeof x)
#define ninf(x) memset(x,0xc0,sizeof x)
#define st0(x) memset(x,false,sizeof x)
#define st1(x) memset(x,true,sizeof x)
#define INF 0x3f3f3f3f
#define lowbit(x) x&(-x)
#define bug cout<<"here"<<endl;
//#define debug
const int maxn=100100;

int n,m;
struct road
{
    int to;
    int color;
    road(){}
    road(int _to,int _color):to(_to),color(_color){}
};
vector<road> G[maxn];

int dist[maxn];

int BFS1()
{
    inf(dist);
    dist[n]=0;
    queue<int> que;
    que.push(n);
    while(que.size())
    {
        int p=que.front();
        que.pop();
        for(int i=0;i<G[p].size();++i)
        {
            if(dist[G[p][i].to]>dist[p]+1)
            {
                dist[G[p][i].to]=dist[p]+1;
                que.push(G[p][i].to);
            }
        }
    }
    return dist[1];
}

int idealpath[maxn];

struct node2
{
    int pos;
    int steps;
    int color;
    node2(){}
    node2(int _pos,int _steps,int _color):pos(_pos),steps(_steps),color(_color){}
};

bool visit[maxn];
void BFS2()
{
    queue<node2> que;
    que.push(node2(1,0,0));
    inf(idealpath);
    idealpath[0]=0;
    st0(visit);
    while(que.size())
    {
        node2 p=que.front();
        //cout<<p.pos<<endl;
        que.pop();
        if(p.color>idealpath[p.steps]||visit[p.pos])
            continue;
        visit[p.pos]=1;
        for(int i=0;i<G[p.pos].size();++i)
            if(dist[p.pos]==dist[G[p.pos][i].to]+1&&idealpath[p.steps+1]>=G[p.pos][i].color)
                que.push(node2(G[p.pos][i].to,p.steps+1,idealpath[p.steps+1]=G[p.pos][i].color));
    }
    return;
}


int main()
{
    #ifdef debug
        freopen("E:\\Documents\\code\\input.txt","r",stdin);
        freopen("E:\\Documents\\code\\output.txt","w",stdout);
    #endif
    while(cin>>n>>m)
    {
        int a,b,c;
        for(int i=1;i<=n;++i)
            G[i].clear();
        while(m--)
        {
            cin>>a>>b>>c;
            G[a].push_back(road(b,c));
            G[b].push_back(road(a,c));
        }
        int res=BFS1();
        cout<<res<<endl;
        BFS2();
        for(int i=1;i<=res-1;++i)
            cout<<idealpath[i]<<" ";
        cout<<idealpath[res]<<endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值