POJ 3469最大流最小割原理(Dinic多路增广)

题目描述:
由于越来越多的计算机配置了双核CPU,TinySoft 公司的首席技术官员,SetagLilb,决定升级他们的产品-SWODNIW。SWODNIW 包含了N 个模块,每个模块必须运行在某个CPU 中。每个模块在每个CPU 中运行的耗费已经被估算出来了,设为Ai 和Bi。同时,M 对模块之间需要共享数据,如果他们运行在同一个CPU 中,共享数据的耗费可以忽略不计,否则,还需要额外的费用。你必须很好地安排这N 个模块,使得总耗费最小。
输入描述:
测试数据的第1 行为两个整数N 和M,1≤N≤20000,1≤M≤200000。接下来有N 行,每行为两个整数Ai 和Bi。接下来有M 行,每行为3 个整数a, b, w,表示a 模块和b 模块如果不是在同一个CPU 中运行,则需要花费额外的w 耗费来共享数据。

输出描述:输出一个整数,为最小耗费。
样例输入: 
3 1
1 10
2 10
10 3
2 3 1000

样例输出:

13


这题有点神了,Dinic算法TLE了好多发啊!!!Dinic这T得无语了!后面实在不行看别人博客了!原来Dinic还有多路增广这做法,太神了!!!

就是在dfs的时候多路增广……好神……做为网络流更快的模板了……再学习下sap优化就差不多了……

这题还有点其实就是构图刚开始的时候我是有向图的,然后做着做着得有反向边啊,然后想了想,原来就是无向图而已……有向边加上其反向边就是一个强连通了,那么相当于没有方向一样了……

#include <iostream>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <deque>
#include <vector>
#include <list>
#include <queue>
#include <string>
#include <cstring>
#include <map>
#include <set>
#define PI acos(-1.0)
#define mem(a,b) memset(a,b,sizeof(a))
#define sca(a) scanf("%d",&a)
#define pri(a) printf("%d\n",a)
#define MM 1000002
#define MN 22005
#define INF 168430090
using namespace std;
typedef long long ll;
int n,m,cnt,d[MN],head[MM],go[MM],q[MM];
struct node
{
    int v,w,next;
}e[MM];
void add(int u,int v,int w)
{
    e[cnt].v=v; e[cnt].w=w; go[cnt]=cnt+1; //go数组的作用是记住反向边的邻接表下标,下同
    e[cnt].next=head[u]; head[u]=cnt++;
    e[cnt].v=u; e[cnt].w=0; go[cnt]=cnt-1; //反向边权值为0
    e[cnt].next=head[v]; head[v]=cnt++;
}
int bfs()
{
    mem(d,-1);
    int left=0,right=0;
    q[right++]=0; d[0]=0;
    while(left<right)  //找增广路
    {
        int u=q[left++];
        for(int v=head[u];v!=-1;v=e[v].next)
        {
            if(d[e[v].v]==-1&&e[v].w)
            {
                d[e[v].v]=d[u]+1; //分层,越往后,层数越大
                if(e[v].v!=n+1) q[right++]=e[v].v;
            }
        }
    }
    return d[n+1]!=-1;
}
int dfs(int u,int Min)
{
    int sum,duolu=0;
    if(u==n+1) return Min;
    for(int v=head[u];v!=-1&&Min-duolu>0;v=e[v].next)  //Min-duolu这个多路增广的做法真神!
        if(e[v].w&&d[e[v].v]==d[u]+1&&(sum=dfs(e[v].v,min(Min-duolu,e[v].w))))
        {
            e[v].w-=sum;
            e[go[v]].w+=sum;
            duolu+=sum;
        }
    return duolu;
}
void Dinic()
{
    int tmp,ans=0;
    while(bfs())
    {
        while(tmp=dfs(0,INF))
            ans+=tmp;
    }
    printf("%d\n",ans);
}
int main()
{
    scanf("%d%d",&n,&m);
    int u,v,w,i,a,b;
    mem(head,-1);
    for(i=1;i<=n;i++)
    {
        scanf("%d%d",&a,&b);
        add(0,i,a); add(i,n+1,b);
    }
    while(m--)
    {
        scanf("%d%d%d",&u,&v,&w);
        add(u,v,w);
    }
    Dinic();
    return 0;
}


你可能感兴趣的:(POJ 3469最大流最小割原理(Dinic多路增广))