UVA 10806 Dijkstra, Dijkstra

重点讲一下每一条无向边变成2条有向边的正确性

 (1)这样不会使本应无解的情况有解:一条边是S-->A->B-->T,另一条边是S从虚线到A,A->B,B从虚线到T,看似AB边走了2次,其实此时可以S-->A-->T,  S-->B-->T,不走AB,确实有解。

(2)这样不会得到比正确的最小值更小的解。假如因为AB边走了2次而得到更小的解,那么同  (1)可以知道,不走AB的方法一定可以有更小的解(且合法)(因为cost一定是正的)

//#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<algorithm>
#include<vector>
#include<string.h>
#include<queue>
#include<assert.h>
#include<stack>
using namespace std;
const int maxn = 100+ 5;
const int INF = 1e9;
struct edge
{
	int from, to, cap, flow, cost;
};
struct MCMF
{
	int inq[maxn];
	int d[maxn];
	int p[maxn];
	int a[maxn];
	int n, m;
	vector<int> G[maxn];
	vector<edge> edges;

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

	void add_edge(int from, int to, int c, int cost)
	{
		edges.push_back(edge{ from,to,c,0,cost });
		edges.push_back(edge{ to,from,0,0,-cost });
		m = edges.size();
		G[from].push_back(m - 2);
		G[to].push_back(m - 1);
	}

	bool bellmanford(int s, int t, int& flow, int& cost)
	{
		for (int i = 0; i <= n; i++)d[i] = INF;
		d[s] = 0; inq[s] = 1; a[s] = INF;
		queue<int> q; q.push(s);

		while (!q.empty())
		{
			int x = q.front(); q.pop();
			inq[x] = 0;
			for (int i = 0; i < G[x].size(); i++)
			{
				edge& e = edges[G[x][i]];
				int v = e.to;
				if (e.cap > e.flow && d[v] > d[x] + e.cost)
				{
					d[v] = d[x] + e.cost;
					p[v] = G[x][i];
					a[v] = min(a[x], e.cap - e.flow);
					if (!inq[v])
					{
						inq[v] = 1; q.push(v);
					}
				}

			}
		}

		if (d[t] == INF)return 0;
		flow += a[t];
		cost += (a[t] * d[t]);
		int v = t;
		while (v != s)
		{
			edges[p[v]].flow += a[t];
			edges[p[v] ^ 1].flow -= a[t];
			v = edges[p[v]].from;
		}
		return 1;
	}

	int mincost(int s, int t,int& flow)
	{
		flow = 0; int cost = 0;
		while(bellmanford(s,t,flow,cost)){}
		return cost;
	}
}mc;
int n,m;
int main()
{
	while (cin >> n&&n)
	{
		
		mc.init(n);
		cin >> m;
		for (int i = 0; i < m; i++)
		{
			int u, v, d; cin >> u >> v >> d;
			mc.add_edge(u, v, 1, d);
			mc.add_edge(v, u, 1, d);
		}
		mc.add_edge(0, 1, 2, 0);
		int flow = 0;
		int cost=mc.mincost(0, n,flow);
		if (flow < 2)
		{
			cout << "Back to jail" << endl;
		}
		else
		{
			cout << cost << endl;
		}
	}
	return 0;
}

  • 9
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值