洛谷P2046 海拔

链接

海拔

题解

平面图最小割,转成对偶图最短路即可。

代码

#include <bits/stdc++.h>

using namespace std;

#define REP(i, n) for (int i = 1; i <= (n); i++)
#define sqr(x) ((x) * (x))
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1

const int maxn = 500000 + 100;
// const int maxn = 50;
const int maxm = 500 + 10;
// const int maxm = 100;
const int maxt = 3000000 + 100;
const int maxk = 10 + 3;

typedef long long LL;
typedef long double LD;
typedef unsigned long long uLL;
typedef pair<int, int> pii;
typedef pair<double, double> pdd;

const LL unit = 1LL;
const int INF = 0x3f3f3f3f;
const LL Inf = 0x3f3f3f3f3f3f3f3fLL;
const double eps = 1e-4;
const double inf = 1e15;
const double pi = acos(-1.0);
const LL mod = 1000000007;
const int dir[][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};

inline int read()
{
	register int x = 0, t = 1;
	register char ch = getchar();
	while ((ch < '0' || ch > '9') && ch != '-')
		ch = getchar();
	if (ch == '-')
		t = -1, ch = getchar();
	while (ch <= '9' && ch >= '0')
		x = x * 10 + ch - 48, ch = getchar();
	return x * t;
}

//n 是点的个数, m是边的个数
//st是源点
//每次AddEdge加的是有向边,无向边需加两次

struct Dijkstra
{
	struct Edge
	{
		int from, to, dis;
	};

	struct HeapNode
	{
		int u, dis;
		bool operator<(const HeapNode &a) const
		{
			return dis > a.dis;
		}
	};

	int n, m;
	vector<Edge> edge;
	vector<int> G[maxn];
	bool vis[maxn]; //是否永久标号
	int dist[maxn]; //最短距离
	int pre[maxn];  //最短路中上一条边

	void init(int n)
	{
		this->n = n;
		for (int i = 0; i < n; i++)
			G[i].clear();
		edge.clear();
	}

	void AddEdge(int from, int to, int d)
	{
		edge.push_back((Edge){from, to, d});
		m = edge.size();
		G[from].push_back(m - 1);
	}

	void dijkstra(int st)
	{
		priority_queue<HeapNode> que;
		for (int i = 0; i < n; i++)
			dist[i] = INF;
		dist[st] = 0;
		memset(vis, false, sizeof(vis));
		que.push((HeapNode){st, 0});
		while (!que.empty())
		{
			HeapNode x = que.top();
			que.pop();
			int u = x.u;
			if (vis[u])
				continue;
			vis[u] = true;

			for (int i = 0; i < G[u].size(); i++)
			{
				Edge &e = edge[G[u][i]];
				int v = e.to;
				if (dist[v] > dist[u] + e.dis)
				{
					dist[v] = dist[u] + e.dis;
					que.push((HeapNode){v, dist[v]});
					pre[v] = G[u][i];
				}
			}
		}
	}
} solver;

int n, tot;
int id[maxm][maxm];

int main()
{
	n = read();
	for (int i = 1; i <= n; ++i)
		for (int j = 1; j <= n; ++j)
			id[i][j] = ++tot;
	int st = 0, en = tot + 1;
	solver.init(tot + 2);
	for (int i = 1; i <= n; ++i)
		id[i][0] = id[n + 1][i] = st;
	for (int i = 1; i <= n; ++i)
		id[0][i] = id[i][n + 1] = en;
	for (int i = 1; i <= n + 1; ++i)
		for (int j = 1; j <= n; ++j)
			solver.AddEdge(id[i][j], id[i - 1][j], read());
	for (int i = 1; i <= n; ++i)
		for (int j = 1; j <= n + 1; ++j)
			solver.AddEdge(id[i][j - 1], id[i][j], read());
	for (int i = 1; i <= n + 1; ++i)
		for (int j = 1; j <= n; ++j)
			solver.AddEdge(id[i - 1][j], id[i][j], read());
	for (int i = 1; i <= n; ++i)
		for (int j = 1; j <= n + 1; ++j)
			solver.AddEdge(id[i][j], id[i][j - 1], read());
	solver.dijkstra(st);
	printf("%d\n", solver.dist[en]);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值