Java教程

分层图模板题

本文主要是介绍分层图模板题,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

感谢所有AC

分层图形式

传送门

思路

       建立分层图,即复制 $k + 1$ 张图,层与层之间建立零权边。对源点进行 $dijstra$ ,得出源点到分层图上任意一点的最短路。由于最优方案并非要把所有次数用完,所以最后需要取终点的所有可能的最小值。需要注意空间大小,如果数据过大无法使用。

       该题为模板题,无特殊。

代码

#include<iostream>
#include<cstring>
#include<queue>
#define maxn 50050
using namespace std;
struct edge {
	int to, val, nxt;
}g[maxn*44];
struct node {
	int s, w;
	bool operator<(const node& a)const {
		if (w != a.w)return w > a.w;
		else return s < a.s;
	}
};
priority_queue<node> q;
int cnt, hd[maxn*11], dis[maxn * 11], u, v, w, n, m, s, t, k, ans = INT32_MAX;
bool vis[maxn * 11];
void add(int u, int v, int w)
{
	g[++cnt].val = w;
	g[cnt].to = v;
	g[cnt].nxt = hd[u];
	hd[u] = cnt;
}
int main(void)
{
	ios::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	cin >> n >> m >> k >> s >> t;
	for (int i = 1; i <= m; i++)
	{
		cin >> u >> v >> w;
		add(u, v, w);
		add(v, u, w);
		for (int j = 1; j <= k; j++)
		{
			add(u + j * n, v + j * n, w);
			add(v + j * n, u + j * n, w);
			add(u + j * n - n, v + j * n, 0);
			add(v + j * n - n, u + j * n, 0);
		}
	}
	memset(dis, 63, sizeof(dis));
	dis[s] = 0;
	q.push({ s,0 });
	while (!q.empty())
	{
		int u = q.top().s;
		q.pop();
		if (vis[u])continue;
		vis[u] = true;
		for (int i = hd[u]; i; i = g[i].nxt)
			if (dis[g[i].to] > dis[u] + g[i].val && !vis[g[i].to])
			{
				dis[g[i].to] = dis[u] + g[i].val;
				q.push({ g[i].to,dis[g[i].to] });
			}
	}
	for (int i = 0; i <= k; i++)
		ans = min(ans, dis[t + i * n]);
	cout << ans;
	return 0;
}

DP形式

传送门

思路

       DP思想,定义状态 $f(i,j)$ 为到达点 $i$ ,花费 $j$ 次机会的最短路径。在优先队列中多加入一个 $cost$ 的变量来限制使用机会的次数。在松弛操作中比朴素的 $dijstra$ 要多一个使用一次机会的情况。对空间的要求比分层图小得多,可以优先考虑。

       该题为 $dijstra$ 的变种,最短路径是整条路径的最大权值,在松弛时需要拿当前路径和两点间权值的最大值来操作。

代码

#include<iostream>
#include<queue>
#include<cstring>
#define maxn 1007
using namespace std;
struct edge {
    int to, val, nxt;
}g[maxn*20];
struct node {
    int s, c;
    long long w;
    bool operator <(const node& a)const {
        return w > a.w;
    }
};
int hd[maxn], cnt, n, m, k, u, v, w;
bool vis[maxn][maxn];
long long dis[maxn][maxn];
priority_queue<node> q;
void add(int u, int v, int w)
{
    g[++cnt].val = w;
    g[cnt].to = v;
    g[cnt].nxt = hd[u];
    hd[u] = cnt;
}
int main(void)
{
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cin >> n >> m >> k;
    for (int i = 1; i <= m; i++)
    {
        cin >> u >> v >> w;
        add(u, v, w);
        add(v, u, w);
    }
    memset(dis, 64, sizeof(dis));
    dis[1][0] = 0;
    q.push({ 1,0,0 });
    long long ans = dis[0][0];
    while (!q.empty())
    {
        int u = q.top().s, cost = q.top().c;
        q.pop();
        if (vis[u][cost])continue;
        vis[u][cost] = true;
        for (int i = hd[u]; i; i = g[i].nxt)
        {
            int v = g[i].to;
            if (dis[v][cost] > max((long long)g[i].val,dis[u][cost]) && !vis[v][cost])
            {
                dis[v][cost] = max((long long)g[i].val,dis[u][cost]);
                q.push({ v, cost, dis[v][cost] });
            }
            if (dis[v][cost + 1] > dis[u][cost] && cost < k && !vis[v][cost + 1])
            {
                dis[v][cost + 1] = dis[u][cost];
                q.push({ v,cost + 1,dis[v][cost + 1] });
            }
        }
    }
    for (int i = 0; i <= k; i++)
        ans = min(ans, dis[n][i]);
    if (ans == dis[0][0])cout << -1;
    else cout << ans;
    return 0;
}

 

这篇关于分层图模板题的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!