您的位置:首页 > 其它

最小费spfa()+ek() 邻接表

2015-09-05 10:18 351 查看
/**
    贴下最小费的邻接表模板

    图算法中邻接表应用极其广泛,在速度和边处理方面都要比矩阵好很多

    最小费邻接矩阵模板前面提到了 就不多说了
    包括添边等常用的技巧前面也都提到了

    就是求网络流是会用到逆流边
    用邻接表添边,逆流边也相当经典,这个技巧刚开始并不好理解

    比如:设edge[p] = ab; 则逆流边为 edge[p^1] = ba;

    p^1 这是个什么东西?? ^ 这个符号是异或,p^1 = ???
    如果p 为偶数则 p^1 = p+1, 如果p 为奇数 p^1 = p-1;

    所以p^1 总能得到一个与自己相邻的数
    把这个现象用到解决逆流边上面,因为添边时候的下一条边就为逆流边
    所以如果从一个偶数开始

    比如:从2开始 edge[2] = ab;  edge[3] = ba; edge[4] = bc; edge[5] = cb;

    每次都会添两条边,所以下一条边开始必为偶数 p ,而它的逆流边即为 p^1

    具体看代码
*/

struct {
    int v, cap, cost, next;
}edge[eM];  //边结构体 eM为 最多有多少条边

int ne, edgeHead[nM]; //nM为 点的个数
int pre[nM];          //用来记录增广路径

int ans, ne;

void addEdge(int u, int v, int c, int w) {
    edge[ne].v = v;
    edge[ne].cap = c;
    edge[ne].cost = w;
    edge[ne].next = edgeHead[u];
    edgeHead[u] = ne++;

    edge[ne].v = u;
    edge[ne].cap = 0;
    edge[ne].cost = -w;
    edge[ne].next = edgeHead[v];
    edgeHead[v] = ne++;
}

bool spfa(int s, int t) {
    //spfa算法前面也介绍过,这里用的栈模式,还有一个队列版,简单修改下就能得到
    //一定要记住有时栈会超时,有时队列也会超时,总有一个能过
    int dis[nM], stack[nM], vis[nM];
    int i, top = 0;
    for (i=0; i<=n; i++) {
        dis[i] = inf;
        vis[i] = false;
    }
    dis[s] = 0;
    stack[++top] = s;
    vis[s] = true;
    while (top) {
        int u = stack[top--];
        for (i=edgeHead[u]; i!=0; i=edge[i].next) {
            int v = edge[i].v;
            if (edge[i].cap && dis[v] > dis[u] + edge[i].cost) {
                dis[v] = dis[u] + edge[i].cost;
                pre[v] = i;     //记录路径用的是边号,所以 u = edge[p^1].v;
                if (!vis[v]) {
                    vis[v] = true;
                    stack[++top] = v;
                }
            }
        }
        vis[u] = false;
    }
    if (dis[t] < inf)   return true;
    return false;
}

void end(int s, int t) {
    //这些原理和邻接矩阵一模一样
    int u, p, sum = inf;
    for (u=t; u!=s; u=edge[p^1].v) {
        p = pre[u];
        sum = min(sum, edge[p].cap);
    }
    for (u=t; u!=s; u=edge[p^1].v) {
        //嗯,这个好好模拟下,技巧噢
        p = pre[u];
        edge[p].cap -= sum;
        edge[p^1].cap += sum;
        ans += edge[p].cost * sum;
    }
}

int main() {
    //初始化
    memset(edgeHead, 0, sizeof (edgeHead));
    ne = 2; //一定要从偶数开始,因为edgeHead 初始化为0 了所以赋值为2
    ans = 0; //最小费

    /**
        ***建图添边****
        调用addEdge()添边,uv 表示一条边,c为流量,w为花费
        则 addEdge(u, v, c, w); 即可

        这才是重重之中的技能
        关键在建图,模板都会套
    */

    //调用
    while (spfa(s, t))
        end(s, t);
    //s为源点,t为汇点

    return 0;
}

收藏于 2012-01-12
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: