pku2135 最小费用最大流 EK算法 邻接表实现

Farm Tour

题意简单:FJ有N个农场,M条路,FJ要领朋友游玩,从1走到N,再回到1,不走重复路,每条路长度不一样,问最短路长为多少。

转化为最小费用流来求解,建一源点S,指向节点1,容量为2,距离0,建一汇点T,N节点指向汇点,容量为2,距离为0,表示要有两条路从S到T,其余给定的路,容量为1,边权为路长,表示每条路只走一次。

刚学的最小费用流,用邻接表实现了一下:

#include<stdio.h>

#include<string.h>

#include<stdlib.h>

#define MM 40010

#define NN 1010

#define INF 0xfffffff

typedef struct node{

    int v, f, b;

    struct node *nxt;

}NODE;



NODE edg[MM]; // 存边 

NODE *link[NN]; // i节点形成的链表的首节点,也表示与i节点相邻的第一个节点 

int N, M, edNum, S, T;

int dis[NN];

int mark[NN];

int stack[NN];

int pre[NN];    // 记录最短路径中i节点的前驱顶点 

int preEdg[NN]; // 记录最短路径中以i节点为终点的边 

int Min(int a, int b){

    return a < b ? a : b;

}



void add(int u, int v, int b, int f){// 用邻接表存 

	edg[edNum].v = v;

    edg[edNum].f = f;

    edg[edNum].b = b;

    edg[edNum].nxt = link[u];

    link[u] = edg + edNum++;

}



int Spfa(){

    int top, u, v, i;

    for (i = 0; i <= N + 1; i++){

        mark[i] = 0;

        dis[i] = INF;

    }

    dis[0] = 0;

    stack[1] = S;

    mark[S] = 1;

    top = 1;

    while(top){

        u = stack[top--];

        mark[u] = 0;  // 记得置零 

        for (NODE *p = link[u]; p; p = p->nxt){

            v = p->v;

            if (p->f && dis[v] > dis[u] + p->b){

				dis[v] = dis[u] + p->b;

				pre[v] = u;

				preEdg[v] = p - edg;

				if (!mark[v]){

					mark[v] = 1;

					stack[++top] = v;

				}

            }

        }

    }

    

    return dis[T];

}

int MinCostMaxFlow()

{

    int c, t, e, rev, minf, ans = 0;

    while((c = Spfa()) != INF){

        minf = INF;

        t = T;

        while(t != S){  // 求得最短路径中的最小流值的增量 

			e = preEdg[t];

            minf = Min(minf, edg[e].f);

            t = pre[t];

        }

        t = T;

        while(t != S){

			e = preEdg[t];

            edg[e].f -= minf;

            rev = e + 1 + (-2) * (e % 2); // 求反向边 

            edg[rev].f += minf;

            edg[rev].b = -edg[e].b;

            t = pre[t];

        }

        ans += minf * c;

    }

	return ans;

}

int main()

{

    int u, v, c;

    scanf("%d%d", &N, &M);

    memset(link, 0, sizeof(link));

    while(M--){

        scanf("%d%d%d", &u, &v, &c);

        add(u, v, c, 1);

        add(v, u, INF, 0);

        add(v, u, c, 1);

        add(u, v, INF, 0);

    }

    S = 0; // 源点 

    T = N + 1; // 汇点 

    add(S, 1, 0, 2);

    add(1, S, INF, 0);

    add(N, T, 0, 2);

    add(T, N, INF, 0);

    printf("%d\n", MinCostMaxFlow());

   // system("pause");

    return 0;

}

你可能感兴趣的:(pku)