HOJ 2739 The Chinese Postman Problem

来源:互联网 发布:仅退款淘宝无法介入 编辑:程序博客网 时间:2024/06/01 08:44

题目:

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

32 10 1 34 40 1 11 2 22 3 33 0 44 70 1 11 2 22 3 33 0 41 3 53 1 21 3 2

Sample Output

-11021

大意:

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

思路:

若原图的基图不连通,或者存在某个点的入度或出度为0则无解。统计所有点的入度出度之差Di,对于Di > 0的点,加边(s, i, Di, 0);对于Di < 0的点,加边(i, t, -Di, 0);对原图中的每条边(i, j),在网络中加边(i, j, ∞, Dij),其中Dij为边(i, j)的权值。求一次最小费用流,费用加上原图所有边权和即为结果。
若进一步要求输出最小权值回路,则对所有流量fij > 0的边(i, j),在原图中复制fij份,这样原图便成为欧拉图,求一次欧拉回路即可。

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <queue>using namespace std;const int MAXN=100+10;const int inf=1e9;int n,m;int s,e;int in[MAXN],out[MAXN];int cnt,head[MAXN];struct node{    int u,v,w,f,next;} edge[8000];void init(){    cnt=0;    for(int i=0; i<=e; ++i)    {        head[i]=-1;        in[i]=0;        out[i]=0;    }}void add(int u,int v,int w,int f){    edge[cnt].u=u;    edge[cnt].v=v;    edge[cnt].w=w;    edge[cnt].f=f;    edge[cnt].next=head[u];    head[u]=cnt++;    edge[cnt].u=v;    edge[cnt].v=u;    edge[cnt].w=-w;    edge[cnt].f=0;    edge[cnt].next=head[v];    head[v]=cnt++;}bool vis[MAXN];int dis[MAXN],pre[MAXN];bool spfa(){    int i;    for(i=0; i<=e; ++i)    {        dis[i]=inf;        pre[i]=-1;        vis[i]=0;    }    queue<int>q;    q.push(0);    dis[0]=0;    while(!q.empty())    {        int u=q.front();        q.pop();        vis[u]=0;        for(i=head[u]; i!=-1; i=edge[i].next)        {            int v=edge[i].v;            int w=edge[i].w;            int f=edge[i].f;            if(f>0&&dis[v]>dis[u]+w)            {                dis[v]=dis[u]+w;                pre[v]=i;                if(!vis[v])                {                    vis[v]=1;                    q.push(v);                }            }        }    }    if(pre[e]==-1)return 0;    return 1;}int get_mincost(){    int max_flow=0,min_cost=0;    while(spfa())    {        int p=pre[e];        int flow=inf;        while(p!=-1)        {            flow=min(flow,edge[p].f);            p=pre[edge[p].u];        }        max_flow+=flow;        min_cost+=flow*dis[e];        p=pre[e];        while(p!=-1)        {            edge[p].f-=flow;            edge[p^1].f+=flow;            p=pre[edge[p].u];        }    }    return min_cost;}int main(){    int i;    int t;    scanf("%d",&t);    while(t--)    {        scanf("%d%d",&n,&m);        s=0,e=n+1;        init();        int u,v,w;        int sum=0;        while(m--)        {            scanf("%d%d%d",&u,&v,&w);            out[++u]++;            in[++v]++;            add(u,v,w,inf);            sum+=w;        }        for(i=1;i<=n;++i)        {            if(!in[i]||!out[i])break;            int d=in[i]-out[i];            if(d>0)            {                add(s,i,0,d);            }            else if(d<0)            {                add(i,e,0,-d);            }        }        if(i<=n)puts("-1");        else printf("%d\n",sum+get_mincost());    }    return 0;}






1 0
原创粉丝点击