The Chinese Postman Problem

My Tags   (Edit)
  Source : bin3
  Time limit : 1 sec   Memory limit : 64 M

Submitted : 503, Accepted : 172

A Chinese postman is assigned to a small town in China to deliver letters. In this town, each street is oriented and connects exactly two junctions. The postman's task is to start at the post office and pass each street at least once to deliver letters. At last, he must return to the post office.

Can you help him to make sure whether there exist feasible routes for him and find the minimum distance from all the feasible routes.

Input

Input contains multiple test cases. The first line is an integer T, the number of test cases. Each case begins with two integers N, M, with 2 ≤ N ≤ 100, 1 ≤ M ≤ 2000, representing the number of junctions and the number of streets respectively.

Then M lines will follow, each denoting a street. A street is represented by three integers u, v, d, with 0 ≤ u, v < N, 0 < d ≤ 1000, meaning this street whose length is d connects the junction u and v and the postman can only travel from junction u to v. Junctions are numbered from 0 to N-1. Junction 0 is always the post office. Note that there may be more than one street connecting the same pair of junctions.

Output

Output one line for each test case. If there exist feasible routes for the postman, output the minimum distance. Otherwise, output -1.

Sample Input

3
2 1
0 1 3
4 4
0 1 1
1 2 2
2 3 3
3 0 4
4 7
0 1 1
1 2 2
2 3 3
3 0 4
1 3 5
3 1 2
1 3 2

Sample Output

-1
10
21

题目链接:HIT 2739

题意就是用最少的费用把所有边跑一边,并最终回到源点,这个跟欧拉回路有一点关系,有向图欧拉回路的充要条件就是所有点的出度和入度相等,并且基图要连通,这题的边方向已经是不能改的了,因此只能通过重复走来使得到达另一些重边,即多走几遍一些边,把某些点的出度和入度补成一样的,那么可以统计所有点的入度和出度之差记为$deg_i=in_i-out_i$,如果一个点$deg_i>0$,说明这个点的入度比较大,需要补充一些,因此要和源点连边;若$deg_i<0$即入度较大,则和汇点连边,这样一来就就可以构图使得流量从入度多的点流向出度多的点,平衡了入度和出度。

代码:

#include <stdio.h>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <bitset>
#include <string>
#include <stack>
#include <cmath>
#include <queue>
#include <set>
#include <map>
using namespace std;
#define INF 0x3f3f3f3f
#define LC(x) (x<<1)
#define RC(x) ((x<<1)+1)
#define MID(x,y) ((x+y)>>1)
#define fin(name) freopen(name,"r",stdin)
#define fout(name) freopen(name,"w",stdout)
#define CLR(arr,val) memset(arr,val,sizeof(arr))
#define FAST_IO ios::sync_with_stdio(false);cin.tie(0);
typedef pair<int, int> pii;
typedef long long LL;
const double PI = acos(-1.0);
const int N = 110;
const int M = 2010;
struct edge
{
int to, nxt, cap, cost;
edge() {}
edge(int _to, int _nxt, int _cap, int _cost): to(_to), nxt(_nxt), cap(_cap), cost(_cost) {}
} E[(M + N) << 1];
int head[N], tot;
int d[N], pre[N], pat[N], mc, mf;
bitset<N>vis;
int n, m, deg[N]; void init()
{
CLR(head, -1);
tot = 0;
mc = mf = 0;
CLR(deg, 0);
}
inline void add(int s, int t, int cap, int cost)
{
E[tot] = edge(t, head[s], cap, cost);
head[s] = tot++;
E[tot] = edge(s, head[t], 0, -cost);
head[t] = tot++;
}
int spfa(int s, int t)
{
queue<int>Q;
Q.push(s);
CLR(d, INF);
vis.reset();
vis[s] = 1;
d[s] = 0;
while (!Q.empty())
{
int u = Q.front();
Q.pop();
vis[u] = 0;
for (int i = head[u]; ~i; i = E[i].nxt)
{
int v = E[i].to;
if (d[v] > d[u] + E[i].cost && E[i].cap > 0)
{
d[v] = d[u] + E[i].cost;
pre[v] = u;
pat[v] = i;
if (!vis[v])
{
vis[v] = 1;
Q.push(v);
}
}
}
}
return d[t] != INF;
}
void MCMF(int s, int t)
{
int i;
while (spfa(s, t))
{
int df = INF;
for (i = t; i != s; i = pre[i])
df = min(df, E[pat[i]].cap);
for (i = t; i != s; i = pre[i])
{
E[pat[i]].cap -= df;
E[pat[i] ^ 1].cap += df;
}
mf += df;
mc += df * d[t];
}
}
namespace DSU
{
int pre[N], num;
void init()
{
CLR(pre, -1);
num = n;
}
int Find(int n)
{
return pre[n] == -1 ? n : pre[n] = Find(pre[n]);
}
void Merge(int a, int b)
{
int fa = Find(a), fb = Find(b);
if (fa == fb)
return ;
pre[fb] = fa;
--num;
}
int isconnect()
{
return num == 1;
}
}
int main(void)
{
int T, a, b, w, i;
scanf("%d", &T);
while (T--)
{
init();
scanf("%d%d", &n, &m);
DSU::init();
int ori = 0;
for (i = 0; i < m; ++i)
{
scanf("%d%d%d", &a, &b, &w);
DSU::Merge(a, b);
add(a, b, INF, w);
ori += w;
--deg[a];
++deg[b];
}
if (!DSU::isconnect())
puts("-1");
else
{
int S = n, T = n + 1;
int sf = 0;
for (i = 0; i < n; ++i)
{
if (deg[i] > 0)
add(S, i, deg[i], 0);
else if (deg[i] < 0)
{
add(i, T, -deg[i], 0);
sf -= deg[i];
}
}
MCMF(S, T);
printf("%d\n", mf == sf ? mc + ori : -1);
}
}
return 0;
}

HITOJ 2739 The Chinese Postman Problem(欧拉回路+最小费用流)的更多相关文章

  1. HIT 2739 - The Chinese Postman Problem - [带权有向图上的中国邮路问题][最小费用最大流]

    题目链接:http://acm.hit.edu.cn/hoj/problem/view?id=2739 Time limit : 1 sec Memory limit : 64 M A Chinese ...

  2. The Chinese Postman Problem HIT - 2739(有向图中国邮路问题)

    无向图的问题,如果每个点的度数为偶数,则就是欧拉回路,而对于一个点只有两种情况,奇数和偶数,那么就把都为奇数的一对点  连一条  边权为原图中这两点最短路的值  的边  是不是就好了 无向图中国邮路问 ...

  3. HIT2739 The Chinese Postman Problem(最小费用最大流)

    题目大概说给一张有向图,要从0点出发返回0点且每条边至少都要走过一次,求走的最短路程. 经典的CPP问题,解法就是加边构造出欧拉回路,一个有向图存在欧拉回路的充分必要条件是基图连通且所有点入度等于出度 ...

  4. Chinese Postman Problem Aizu - DPL_2_B(无向图中国邮路问题)

    题意: 带权无向图上的中国邮路问题:一名邮递员需要经过每条边至少一次,最后回到出发点,一条边多次经过权值要累加,问最小总权值是多少.(2 <= N <= 15, 1 <= M < ...

  5. FZU - 2038 -E - Another Postman Problem (思维+递归+回溯)

    Chinese Postman Problem is a very famous hard problem in graph theory. The problem is to find a shor ...

  6. bzoj 1515 [POI2006]Lis-The Postman 有向图欧拉回路

    LINK:Lis-The Postman 看完题觉得 虽然容易发现是有向图欧拉回路 但是觉得很难解决这个问题. 先分析一下有向图的欧拉回路:充要条件 图中每个点的入度-出度=0且整张图是一个强连通分量 ...

  7. Soj题目分类

    -----------------------------最优化问题------------------------------------- ----------------------常规动态规划 ...

  8. LightOJ1086 Jogging Trails(欧拉回路+中国邮递员问题+SPFA)

    题目求从某点出发回到该点经过所有边至少一次的最短行程. 这个问题我在<图论算法理论.实现及应用>中看过,是一个经典的问题——中国邮递员问题(CPP, chinese postman pro ...

  9. 贪心算法:旅行商问题(TSP)

    TSP问题(Traveling Salesman Problem,旅行商问题),由威廉哈密顿爵士和英国数学家克克曼T.P.Kirkman于19世纪初提出.问题描述如下: 有若干个城市,任何两个城市之间 ...

随机推荐

  1. v-for的简单实现

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  2. sql server几种Join的区别测试方法与union表的合并

    /* sql server几种Join的区别测试方法 主要来介绍下Inner Join , Full Out Join , Cross Join , Left Join , Right Join的区别 ...

  3. Mysql5.7.25在windows下安装

    在网上看到了很多安装方法,也试了很多,md,网上资源多了也是有各种坑,这里只说在windows下安装mysql5.7.25 一.下载安装包 链接:https://dev.mysql.com/downl ...

  4. 01U盘PE系统制作方法

    1. 需要的工具和安装包:WinPE镜像文件 WinPE_x86.iso .已制作好的另一个启动盘(下文以映像总裁为例,当然也可以使用大白菜.U启动等) . 电脑.准备制作PE系统的空U盘 2. 还原 ...

  5. 什么是web语义化?

    Web语义化:是指使用语义恰当的标签,使页面有良好的结构,页面元素更有含义,能够让人和搜索引擎都容易理解.使团队项目的可持续运作及维护,去掉样式后页面呈现清晰的结构. 例如:<table> ...

  6. python__系统 : 异步实现以及GIL

    创建进程的方式中有个 callback ,也就是回调. 看代码: from multiprocessing import Pool import time import os def test(): ...

  7. 简单的for循环实现九九乘法表

    PHP for 循环 语法 for (init counter; test counter; increment counter) { code to be executed; } 参数: init ...

  8. python之微信好友统计信息

    需要安装库:wxpy 代码如下: from wxpy import Bot,Tuling,embed,ensure_one bot = Bot(cache_path=True) #获取好友信息 bot ...

  9. pytorch中词向量生成的原理

    pytorch中的词向量的使用 在pytorch我们使用nn.embedding进行词嵌入的工作. 具体用法就是: import torch word_to_ix={'hello':0,'world' ...

  10. storm实时计算实例(socket实时接入)

    介绍 实现了一个简单的从实时日志文件监听,写入socket服务器,再接入Storm计算的一个流程. 源码 日志监听实时写入socket服务器   package socket; import java ...