hdu 4411 最小费用流

思路:主要就是要把一个每个城市拆为两个点,建一条容量为1,费用为-inf的边,保证每个城市都会被遍历。

/*最小费用最大流*/
#include<iostream>
#include<cstring>
#include<cstring>
#include<cmath>
#include<cstdio>
using namespace std;
const int Maxn = 1010;
const int inf = 1000010;
struct Edge{
    int v;
    int val;
    int cost;
    int next;
}edge[Maxn*100];
int head[Maxn],n,g[Maxn][Maxn],m,k;
int e;
int pre[Maxn], pos[Maxn];
int dis[Maxn], que[Maxn*100];
bool vis[Maxn];
void add(int u, int v, int val, int cost)
{
    edge[e].v = v;
    edge[e].val = val;
    edge[e].cost = cost;
    edge[e].next = head[u];
    head[u] = e++;
    edge[e].v = u;
    edge[e].val = 0;
    edge[e].cost = -cost;
    edge[e].next = head[v];
    head[v] = e++;
}
void init()
{
    memset(head,-1,sizeof(head));
    for(int i=0;i<Maxn;i++)
        for(int j=0;j<Maxn;j++)
        g[i][j]=inf;
    e=0;
}
bool spfa(int s, int t)
{
    int i;
    memset(pre, -1, sizeof(pre));
    memset(vis, 0, sizeof(vis));
    int Head, tail;
    Head = tail = 0;
    for(i = 0; i < Maxn; i++)
        dis[i] = inf;
    que[tail++] = s;
    pre[s] = s;
    dis[s] = 0;
    vis[s] = 1;
    while(Head != tail)
    {
        int now = que[Head++];
        vis[now] = 0;
        for(i=head[now]; i != -1; i = edge[i].next)
        {
            int adj = edge[i].v;
            //cout<<now<<" "<<adj<<" "<<dis[now]<<" "<<edge[i].cost<<" "<<dis[adj]<<" "<<edge[i].val<<endl;
            if(edge[i].val > 0 && dis[now] + edge[i].cost < dis[adj])
            {
                dis[adj] = dis[now] + edge[i].cost;
                pre[adj] = now;
                pos[adj] = i;
                if(!vis[adj])
                {
                    vis[adj] = 1;
                    que[tail++] = adj;
                }
            }
        }
    }
    return pre[t] != -1;
}
int MinCostFlow(int s, int t, int flow)
{
    int i;
    int cost = 0;
    flow = 0;
    while(spfa(s, t))
    {
        int f = inf;
        for(i = t; i != s; i = pre[i])
        if (edge[pos[i]].val < f)
            f = edge[pos[i]].val;
            flow += f;
            cost += dis[t] * f;
            for(i = t; i != s; i = pre[i])
            {
                edge[pos[i]].val -= f;
                edge[pos[i] ^ 1].val += f;
            }
       // cout<<cost<<endl;
    }
    return cost;
    // flow是最大流值
}
void floyd()
{
    int i,j,k;
    for(k=0;k<=n;k++)
        for(i=0;i<=n;i++)
        for(j=0;j<=n;j++)
        {
            if(g[k][j]==inf) continue;
           g[i][j]=min(g[i][j],g[i][k]+g[k][j]);
        }
}
void build(int lim)
{
    memset(head,-1,sizeof(head));
    e=0;
    int ss = 0;
    int s = 2*n+1;
    int t = 2*n+2;
    add(s,ss,lim,0);
    for(int i=1;i<=n;i++)
    {
        if(g[0][i] < inf)
        {
            add(ss,i,1,g[0][i]);
            add(i+n,t,1,g[i][0]);
        }
        add(i,i+n,1,-inf);
        for(int j=i+1;j<=n;j++)
        {
            if(g[i][j] < inf)
            {
            add(i+n,j,1,g[i][j]);
            }
        }
    }
    add(ss,t,k,0);
    return;
}
int solve()
{
    int i,j;
    int ans;
    ans=inf;
    build(k);
    ans=min(ans,MinCostFlow(n+n+1,n+n+2,0)+n*inf);
    return ans;
}
int main()
{
    int i,j,u,v,c;
    while(scanf("%d%d%d",&n,&m,&k)!=EOF,n||m||k)
    {
        init();
        for(i=1;i<=m;i++)
        {
            scanf("%d%d%d",&u,&v,&c);
            if(g[u][v]>c)
            g[u][v]=g[v][u]=c;
        }
        floyd();
        printf("%d\n",solve());
    }
    return 0;
}

 

posted @ 2013-08-17 16:50  fangguo  阅读(126)  评论(0编辑  收藏  举报