POJ 3469 最大流

Dual Core CPU
Time Limit: 15000MS Memory Limit: 131072K
Total Submissions: 18948 Accepted: 8179
Case Time Limit: 5000MS

Description

As more and more computers are equipped with dual core CPU, SetagLilb, the Chief Technology Officer of TinySoft Corporation, decided to update their famous product - SWODNIW.

The routine consists of N modules, and each of them should run in a certain core. The costs for all the routines to execute on two cores has been estimated. Let's define them asAi and Bi. Meanwhile,M pairs of modules need to do some data-exchange. If they are running on the same core, then the cost of this action can be ignored. Otherwise, some extra cost are needed. You should arrange wisely to minimize the total cost.

Input

There are two integers in the first line of input data, N and M (1 ≤N ≤ 20000, 1 ≤ M ≤ 200000) .
The next N lines, each contains two integer, Ai andBi.
In the following M lines, each contains three integers: a, b, w. The meaning is that if module a and module b don't execute on the same core, you should pay extraw dollars for the data-exchange between them.

Output

Output only one integer, the minimum total cost.

Sample Input

3 1
1 10
2 10
10 3
2 3 1000

Sample Output

13

Source

 

/*
sap模板:POJ 3469
*/

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<string>
#include<vector>
#include<queue>
#include<ctype.h>
#include<bitset>
#include<map>
# pragma comment (linker,"/STACK:16777216")

using namespace std;

const int MAXN = 1000010;
const int INF  = 2100000000;
const double esp = 1e-9;

int n, m, num;

class Edge
{
  public:

    int u, v, w, next;
};
Edge edge[MAXN];

int fa[MAXN], head[MAXN], cur[MAXN], gap[MAXN], dis[MAXN];
/*
fa记录增广过程一个节点的父亲节点;
head是邻接表的表头;
cur当前弧优化数组;记录当前节点的第一条可能的允许弧;
gap是gap优化数组,gap[i]记录当前距离值为i的节点数;
dis储存节点的距离函数值
*/

void insert(int u, int v, int w)
{
    edge[num].u = u;
    edge[num].v = v;
    edge[num].w = w;
    edge[num].next = head[u];
    head[u] = num;

    num++;

    edge[num].u = v;
    edge[num].v = u;
    edge[num].w = 0;
    edge[num].next = head[v];
    head[v] = num;

    num++;
}
/*
最大流sap函数,传入参数s, t, n分别表示源节点,汇点,节点总数,函数返回网络流图中的最大流
复杂度O(E*V*V)

*/
int sap(int s, int t, int n)
{
        memset(fa, -1, sizeof(fa));
        memcpy(cur, head, sizeof(head));//初始时当前弧就是当前节点的第一条弧
        memset(dis, 0, sizeof(dis));//距离函数初始为0
        memset(gap, 0, sizeof(gap));

            gap[0] = n;//初始时距离为0的节点有n个

            int lowf = INF, top = s, flow = 0;//lowf是增广路上的最小流量,top是增广过程最前端的节点,flow待返回的流量

            while(dis[s] < n)//当汇点不可达时,dis[s]的值会被更改为节点总数n
            {
                bool flag = 0;//标记通过top节点能否找到允许弧

                for(int i = cur[top]; i != -1; i = edge[i].next)//从当前弧开始找允许弧
                {
                    int v = edge[i].v;
                    if(dis[top] == dis[v]+1 && edge[i].w > 0)//找到允许弧
                    {
                        flag = 1;//更改标记
                        cur[top] = i;//更改当前节点的当前弧,下次搜索时从这条弧开始
                        lowf = min(lowf, edge[i].w);//更新增广路上的流量
                        fa[v] = top;//记录父节点
                        top = v;//更改top节点

                        if(top == t)//如果找到终点,说明找到一条增广路,更新总流量
                        {
                            flow += lowf;

                            while(top != s)//沿父节点回溯更新残余网络
                            {
                                top = fa[top];

                                edge[cur[top]].w -= lowf;
                                edge[cur[top]^1].w += lowf;

                            }

                            lowf = INF;//重置最小流量
                        }
                        break;
                    }

                }

                /*
                如果没找到允许弧,撤退,更改当前top节点的距离值
                */
                int mindis;//更改top节点的距离值
                if(!flag)
                {
                    mindis = n;//初始化为节点总数

                    for(int i = head[top]; i != -1; i = edge[i].next)
                    {
                        if(edge[i].w > 0 && dis[edge[i].v] < mindis)//如果top节点能从距离比当前节点的距离更小的节点转移来
                        {
                                mindis = dis[edge[i].v];//更新top节点的距离值
                                cur[top] = i;//修改top节点的当前弧
                        }
                    }
                    if((--gap[dis[top]]) == 0) break;//gap优化,如果节点距离值出现断层,必然找不到增广路,直接退出
                    gap[dis[top] = mindis+1]++;//更新top节点的距离值以及gap数组

                    if(top != s) top = fa[top];//top撤退到它的父节点
                }

            }
            return flow;
}

int main()
{
    //freopen("C:/Users/zts/Desktop/in.txt", "r", stdin);
    while(scanf("%d%d", &n, &m) != -1)
    {

        memset(head, -1, sizeof(head));

        n += 2;
        num = 0;

        int a, b, w;
        for(int i = 2; i <= n-1; i++)
        {
            scanf("%d%d", &a, &b);

            insert(1, i, a);
            insert(i, n, b);
        }

        for(int i = 0; i < m; i++)
        {
            scanf("%d%d%d", &a, &b, &w);

            a += 1; b += 1;

            insert(a, b, w);
            insert(b, a, w);
        }

        int ans = sap(1, n, n);

        printf("%d\n", ans);
    }

    return 0;
}


 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值