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;

}

 

你可能感兴趣的:(HDU)