hdu 3488 Tour Tour

http://acm.hdu.edu.cn/showproblem.php?pid=3488

题意:

把有向图分成不相交的有向环. 且所有点都只被一个有向环覆盖.

有向环所有权值的总和最小是多少

点i拆为i和i+n

源点向i连流量为1,费用为0的边

i+n向汇点连流量为1,费用为0的边

存在有向边i-->j

i向j+n连流量为1,费用为边权的边

最大流保证了每个点用了且仅用一次

n个点,入度与出度均为1,保证了全是环

最小费用流保证比边权和最小

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;

#define N 403
#define M 30401

const int inf=2e9;

int cost;

int tot;
int front[N],to[M<<1],nxt[M<<1],from[M<<1];
int val[M<<1],cap[M<<1];

int dis[N];
bool vis[N];

int src,decc;

void read(int &x)
{
    x=0; char c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
}

void add(int u,int v,int w,int f)
{
    to[++tot]=v; nxt[tot]=front[u]; front[u]=tot; from[tot]=u; cap[tot]=w; val[tot]=f;
    to[++tot]=u; nxt[tot]=front[v]; front[v]=tot; from[tot]=v; cap[tot]=0; val[tot]=-f;
}

int augment(int now,int flow)
{
    vis[now]=true;
    if(now==decc) 
    {
        cost-=dis[src]*flow;
        return flow;
    }
    int delta;
    for(int i=front[now];i;i=nxt[i])
    {
        if(cap[i] && !vis[to[i]] && dis[to[i]]==dis[now]+val[i])
        {
            delta=augment(to[i],min(flow,cap[i]));
            if(delta)
            {
                cap[i]-=delta;
                cap[i^1]+=delta;
                return delta;
            }
        }
    }
    return 0;
}

bool retreat()
{
    if(vis[decc]) return true;
    int mi=inf;
    for(int i=2;i<=tot;++i)
        if(cap[i] && vis[from[i]] && !vis[to[i]]) 
            mi=min(mi,dis[from[i]]+val[i]-dis[to[i]]);
    if(mi==inf) return false;
    for(int i=src;i<=decc;++i)
        if(vis[i]) dis[i]-=mi;
    return true;
}

void zkw()
{
    cost=0;
    memset(dis,0,sizeof(dis));
    do
    {
        memset(vis,false,sizeof(vis));
        augment(src,inf);
    }while(retreat());
    cout<<cost<<'
';
}

int main()
{
    int T;
    read(T);
    int n,m;
    int u,v,w;
    while(T--)
    {
        tot=1;
        memset(front,0,sizeof(front));
        read(n);
        read(m);
        decc=n*2+1;
        for(int i=1;i<=n;++i) add(src,i,1,0);
        for(int i=1;i<=n;++i) add(i+n,decc,1,0);
        while(m--)
        {
            read(u);
            read(v);
            read(w);
            add(u,v+n,1,w);
        }
        zkw();
    }
}

Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)
Total Submission(s): 3765    Accepted Submission(s): 1800


Problem Description
In the kingdom of Henryy, there are N (2 <= N <= 200) cities, with M (M <= 30000) one-way roads connecting them. You are lucky enough to have a chance to have a tour in the kingdom. The route should be designed as: The route should contain one or more loops. (A loop is a route like: A->B->……->P->A.)
Every city should be just in one route.
A loop should have at least two cities. In one route, each city should be visited just once. (The only exception is that the first and the last city should be the same and this city is visited twice.)
The total distance the N roads you have chosen should be minimized.
 
Input
An integer T in the first line indicates the number of the test cases.
In each test case, the first line contains two integers N and M, indicating the number of the cities and the one-way roads. Then M lines followed, each line has three integers U, V and W (0 < W <= 10000), indicating that there is a road from U to V, with the distance of W.
It is guaranteed that at least one valid arrangement of the tour is existed.
A blank line is followed after each test case.
 
Output
For each test case, output a line with exactly one integer, which is the minimum total distance.
 
Sample Input
1 6 9 1 2 5 2 3 5 3 1 10 3 4 12 4 1 8 4 6 11 5 4 7 5 6 9 6 5 4
 
Sample Output
42