• 【题解】[JLOI2011] 飞行路线


    题目信息

    题目来源:CCF 吉林省选 2011;

    在线评测地址:Luogu#4568BZOJ#2763

    运行限制:时间不超过 (1.00 extrm{ms}),空间不超过 (128 extrm{MiB})

    题目描述

    Alice 和 Bob 现在要乘飞机旅行,他们选择了一家相对便宜的航空公司。该航空公司一共在 (n) 个城市设有业务,设这些城市分别标记为 (0)(n−1),一共有 (m) 种航线,每种航线连接两个城市,并且航线有一定的价格。

    Alice 和 Bob 现在要从一个城市沿着航线到达另一个城市,途中可以进行转机。航空公司对他们这次旅行也推出优惠,他们可以免费在最多 (k) 种航线上搭乘飞机。那么 Alice 和 Bob 这次出行最少花费多少?

    输入格式

    第一行三个整数 (n)(m)(k),分别表示城市数,航线数和免费乘坐次数。

    接下来一行两个整数 (s)(t),分别表示他们出行的起点城市编号和终点城市编号。

    接下来 (m) 行,每行三个整数 (a)(b)(c),表示存在一种航线,能从城市 (a) 到达城市 (b),或从城市 (b) 到达城市 (a),价格为 (c)

    输出格式

    输出一行一个整数,为最少花费。

    数据规模与约定

    • 对于 (30\%) 的数据,(2le nle 50)(1le mle 300)(k=0)
    • 对于 (50\%) 的数据,(2le nle 600)(1le mle 6 imes 10^3)(0le kle 1)
    • 对于 (100\%) 的数据,(2le nle 10^4)(1le mle 5 imes 10^4)(0le kle 10)

    保证 (0le s,t,a,ble n)(a e b)(0le cle 10^3)

    分析

    题意很明确,给定一张图,一条路径上最多可以使 (k) 条边权值为 (0),求最短路。

    请注意这道题与 [USACO18JAN-Sliver] Telephone Lines 的区别。这道题的最短路是求和,而那一道题的最短路则是取最大值。这两个区别导致这两题本质不同。

    由于有用了多少条边的信息,我们可以构造分层图。第 (i) 层((0le ile n))为用了 (i) 次使边权为 (0) 的操作。

    只需要使起点为 ((s,0)),求解 ((t,0),(t,1),cdots ,(t,k)) 的最短路并去最小值即可。

    注意事项

    这道题的图是无向图,注意加双向边,同时开两倍空间。

    Code

    图论题,尤其是最短路的代码还是比较好敲的,注意一下细节就行了。

    #include <queue>
    #include <cstdio>
    #include <cctype>
    #include <cstring>
    using namespace std;
    
    const int max_n = 10000, max_m = 50000, max_k = 10, max_l = max_k + 1;
    struct node
    {
    	int id, val;
    
    	node(int _i = 0, int _v = 0) : id(_i), val(_v) { }
    
    	bool operator<(const node& n) const
    	{
    		return val > n.val;
    	}
    };
    
    int hd[max_n*max_l], des[max_m*(max_k+max_l)*2], val[max_m*(max_k+max_l)*2], nxt[max_m*(max_k+max_l)*2], e_cnt = 0; // 存图(2*空间)
    int dis[max_n*max_l], n;
    bool vis[max_n*max_l] = {};
    
    priority_queue<node> q;
    
    inline int mk(int id, int ly) { return id + ly * n; } // 生成节点编号
    
    #define gc getchar
    inline int read() // 快读
    {
    	int c = gc(), t = 1, n = 0;
    	while (isspace(c)) { c = gc(); }
    	if (c == '-') { t = -1, c = gc(); }
    	while (isdigit(c)) { n = n * 10 + c - '0', c = gc(); }
    	return n * t;
    }
    #undef gc
    
    void add_edge(int s, int t, int v)
    {
    	des[e_cnt] = t, val[e_cnt] = v;
    	nxt[e_cnt] = hd[s], hd[s] = e_cnt++;
    }
    
    int main()
    {
    	memset(hd, -1, sizeof(hd));
    	memset(dis, 0x3f, sizeof(dis));
    	
    	n = read();
    	int m = read(), k = read(), s = read(), t = read(), ta, tb, tc, ans = 0x3f3f3f3f;
    	node cur;
    
    	for (int i = 0; i < m; i++)
    	{
    		ta = read(), tb = read(), tc = read();
    
    		for (int j = 0; j < k; j++)
    		{
    			add_edge(mk(ta, j), mk(tb, j), tc); // 层内的边
    			add_edge(mk(tb, j), mk(ta, j), tc);
    
    			add_edge(mk(ta, j), mk(tb, j+1), 0); // 使用一次操作,跨层
    			add_edge(mk(tb, j), mk(ta, j+1), 0);
    		}
    		add_edge(mk(ta, k), mk(tb, k), tc); // 注意总共有 k+1 层
    		add_edge(mk(tb, k), mk(ta, k), tc);
    	}
    
    	q.push(node(mk(s, 0), 0));
    	dis[mk(s,0)] = 0;
    
    	while (!q.empty()) // 最短路
    	{
    		cur = q.top();
    		q.pop();
    		
    		if (!vis[cur.id])
    		{
    			vis[cur.id] = true;
    
    			for (int p = hd[cur.id]; p != -1; p = nxt[p])
    				if (dis[des[p]] > dis[cur.id] + val[p])
    				{
    					dis[des[p]] = dis[cur.id] + val[p];
    
    					if (!vis[des[p]])
    						q.push(node(des[p], dis[des[p]]));
    				}
    		}
    	}
    
    	
    	for (int i = 0; i <= k; i++)
    		if (dis[mk(t,i)] < ans)
    			ans = dis[mk(t, i)]; // 统计最小答案
    	
    	printf("%d
    ", ans); // 输出
    	
    	return 0; // 然后就 AC 了、
    }
    
  • 相关阅读:
    FZU2056 最大正方形(二分答案)
    2014暑期集训个人赛
    2014 acm鞍山现场赛总结
    hdu1853 Cyclic Tour (二分图匹配KM)
    zoj3826 Hierarchical Notation (字符串模拟)
    hdu3047 Zjnu Stadium (并查集)
    hdu4886 TIANKENG’s restaurant(Ⅱ) (trie树或者模拟进制)
    CodeForces 287B Pipeline (水题)
    wpf窗体项目 生成dll类库文件
    sqlserver 汉字转全拼函数
  • 原文地址:https://www.cnblogs.com/5ab-juruo/p/solution-jloi2011-lg4568.html
Copyright © 2020-2023  润新知