(beginer) UVA 最小费用流 1349 Optimal Bus Route Design

A big city wants to improve its bus transportation system. One of the improvement is to add scenic routes which go es through attractive places. Your task is to construct a bus-route-plan for sight-seeing buses in a city.

You are given a set of scenic lo cations. For each of these given lo cations, there should be only one bus route that passes this lo cation, and that bus route should pass this lo cation exactly once. The number of bus routes is unlimited. However, each route should contain at least two scenic lo cations.

From location i to location j , there may or may not be a connecting street. If there is a street from location i to location j , then we say j is an out-neighbor of i . The length of the street from i to j is d(ij) . The streets might be one way. So it may happen that there is a street from i to j , but no street from j to i . In case there is a street from i to j and also a street from j to i , the lengths d (ij) andd (ji) might be different. The route of each bus must follow the connecting streets and must be a cycle. For example, the route of Bus A might be from location 1 to location 2, from location 2 to location 3, and then from location 3 to location 1. The route of Bus B might be from location 4 to location 5, then from location 5 to location 4. The length of a bus route is the sum of the lengths of the streets in this bus route. The total length of the bus-route-plan is the sum of the lengths of all the bus routes used in the plan. A bus-route-plan is optimal if it has the minimum total length. You are required to compute the total length of an optimal bus-route-plan.

Input 

The input file consists of a number of test cases. The first line of each test case is a positive integer n, which is the number of locations. These n locations are denoted by positive integers 1, 2,..., n . The next n lines are information about connecting streets between these lo cations. The i -th line of these nlines consists of an even number of positive integers and a 0 at the end. The first integer is a lo cation jwhich is an out-neighbor of location i , and the second integer is d (ij) . The third integer is another location j' which is an out-neighbor of i , and the fourth integer is d (ij') , and so on. In general, the(2k - 1) th integer is a location t which is an out-neighbor of location i , and the 2k th integer is d (i,t) .

The next case starts immediately after these n lines. A line consisting of a single `0' indicates the end of the input file.

Each test case has at most 99 locations. The length of each street is a positive integer less than 100.

Output 

The output contains one line for each test case. If the required bus-route-plan exists, then the output is a positive number, which is the total length of an optimal bus-route-plan. Otherwise, the output is a letter `N'.

Sample Input 

3 
2 2 3 1 0 
1 1 3 2 0 
1 3 2 7 0  
8 
2 3 3 1 0 
3 3 1 1 4 4 0
1 2 2 7 0 
5 4 6 7 0 
4 4 3 9 0 
7 4 8 5 0 
6 2 5 8 8 1 0
6 6 7 2 0
3 
2 1 0 
3 1 0 
2 1 0
0

Sample Output 

7 
25 
N


题意:给出一个有向图,你需要让每一个点都恰好在一个环中,并且费用要最小。


思路:因为每个点恰好在一个环中,那么每个点的入度和出度就是1,那么我们把一个点拆成入度和出度两个点,然后跑一跑最小费用流就出来了,其实这道题可以用最小权匹配来做,不知道为什么我的程序出现了死循环。。。。


代码:


AC KM算法

#include<iostream>
#include<algorithm>
#include<queue>
#include<cstdio>
#include<string.h>
#include<cstring>
#define LL long long
using namespace std;
const int maxn = 100 * 2 + 5;
const int inf = 1e6;
bool S[maxn], T[maxn];
int lx[maxn], ly[maxn];
int slack[maxn], w[maxn][maxn], link[maxn];
int n;
inline int min(int a, int b) { return a < b ? a : b; }

void input()
{
	for (int i = 0; i < n; ++i)
	for (int j = 0; j < n; ++j)
		w[i][j] = inf;
	for (int i = 0; i < n; ++i)
	{
		int x;
		while (scanf("%d", &x) && x)
		{
			int cost;
			scanf("%d", &cost);
			--x;
			w[i][x] = min(w[i][x], cost);
		}
	}
	for (int i = 0; i < n; ++i)
	for (int j = 0; j < n; ++j)
	{

		w[i][j] = -w[i][j];
		//    cout<<w[i][j]<<endl;
	}
}

bool match(int x)
{
	S[x] = true;
	for (int y = 0; y < n; ++y)
	if (!T[y])
	{
		if (lx[x] + ly[y] == w[x][y])
		{
			T[y] = true;
			if (link[y] == -1 || match(link[y]))
			{
				link[y] = x;
				return true;
			}
		}
		else if (lx[x] + ly[y] > w[x][y])
			slack[y] = min(slack[y], lx[x] + ly[y] - w[x][y]);
	}
	return false;
}

LL KM()
{
	memset(ly, 0, sizeof(ly));
	memset(link, -1, sizeof(link));
	for (int i = 0; i < n; ++i)
	{
		lx[i] = -inf;
		for (int j = 0; j < n; ++j)
		{
			//       printf("%d\n",w[i][j]);
			lx[i] = max(lx[i], w[i][j]);
		}
	}
	for (int x = 0; x < n; ++x)
	{
		while (true)
		{
			for (int i = 0; i < n; ++i)
			{
				S[i] = T[i] = false;
				slack[i] = inf;
			}
			if (match(x)) break;
			int minw = inf;
			for (int i = 0; i < n; ++i)
			if (!T[i]) minw = min(minw, slack[i]);
			for (int i = 0; i < n; ++i)
			{
				if (S[i]) lx[i] -= minw;
				if (T[i]) ly[i] += minw;
			}
		}
	}
	LL ret = 0;
	for (int i = 0; i < n; ++i)
		ret += lx[i] + ly[i];
	return ret;
}

void solve()
{
	LL ret = -KM();
	if (ret >= inf - 100) printf("N\n");
	else printf("%d\n", ret);
}

int main()
{
	while (scanf("%d", &n) == 1)
	{
		if (n == 0) return 0;
		input();
		solve();
	}
}

最小费用流:

#include<iostream>
#include<algorithm>
#include<queue>
#include<cstdio>
#include<vector>
#include<string.h>
#include<cstring>
#define LL long long
using namespace std;
const int maxn=100*2+5;
const int inf=1e8;
int n;
struct Edge
{
    int u,v,w;
    int flow,cap;
    Edge(int u,int v,int cap,int flow,int cost)
    :u(u),v(v),cap(cap),flow(flow),w(cost) {}
};

vector<Edge> edges;
vector<int> G[maxn];

void add(int u,int v,int cap,int cost)
{
    edges.push_back(Edge(u,v,cap,0,cost));
    edges.push_back(Edge(v,u,0,0,-cost));
    int m=edges.size();
    G[u].push_back(m-2);
    G[v].push_back(m-1);
}

struct MCMF
{
    int a[maxn],d[maxn],p[maxn];
    bool inq[maxn];
    int n,s,t;
    void init(int n)
    {
        this->n=n;
    }
    bool spfa(int s,int t,int&flow,int&cost)
    {
        this->s=s,this->t=t;
        for(int i=0;i<n;++i) a[i]=d[i]=inf;
        memset(inq,0,sizeof(inq));
        queue<int> q;
        q.push(s);
        inq[s]=true;
        d[s]=0;
        while(q.size())
        {
            int x=q.front(); q.pop();
            inq[x]=false;
            for(int i=0;i<G[x].size();++i)
            {
                Edge&e=edges[G[x][i]];
                if(e.cap<=e.flow) continue;
                int y=e.v,w=e.w;
                if(d[y]<=d[x]+w) continue;
                d[y]=d[x]+w;
                p[y]=G[x][i];
                a[y]=min(a[x],e.cap-e.flow);
                if(!inq[y]) q.push(y);
                inq[y]=true;
            }
        }
        if(d[t]==inf) return false;
        flow+=a[t];
        cost+=a[t]*d[t];
        int x=t;
        while(x!=s)
        {
            edges[p[x]].flow+=a[t];
            edges[p[x]^1].flow-=a[t];
            x=edges[p[x]].u;
        }
        return true;
    }

    int maxflow(int s,int t,int maxf)
    {
        int flow=0,cost=0;
        while(spfa(s,t,flow,cost));
        if(flow<maxf) return -1;
        return cost;
    }
}solver;

int s,t;
void input()
{
    edges.clear();
    for(int i=0;i<maxn;++i) G[i].clear();
    s=0,t=2*n+1;
    for(int i=0;i<n;++i)
    {
        int x;
        while(scanf("%d",&x)==1)
        {
            if(x==0) break;
            int cost;scanf("%d",&cost);
            add(1+i,x+n,1,cost);
        }
        add(s,1+i,1,0);
        add(n+1+i,t,1,0);
    }
}

void solve()
{
    solver.init(2*n+2);
    int ret=solver.maxflow(s,t,n);
    if(ret==-1) printf("N\n");
    else printf("%d\n",ret);
}

int main()
{
    while(scanf("%d",&n)==1)
    {
        if(n==0) return 0;
        input();
        solve();
    }
    return 0;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值