POJ 3469-Dual Core CPU(Dinic 最大流/最小割演算法)

kewlgrl發表於2016-08-15
Dual Core CPU
Time Limit: 15000MS   Memory Limit: 131072K
Total Submissions: 22932   Accepted: 9983
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 as Ai 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 and Bi.
In the following M lines, each contains three integers: abw. The meaning is that if module a and module b don't execute on the same core, you should pay extra w 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

POJ Monthly--2007.11.25, Zhou Dong

題目意思:

有兩個CPU,它們之間有N個模組,每個模組必須執行在某個CPU中。

每個模組在每個CPU中執行的耗費分別是Ai和Bi。

有M對模組之間需要共享資料,如果它們不是在同一個CPU中執行,需要W的耗費,反之不需要。

如何安排這N個模組能夠使得耗費最小?

解題思路:

因為每個模組必須執行在某個CPU中,所以想到要建圖求最小割,又由最大流最小割定理可知,直接求出最大流即可。

注意要雙邊建圖


兩塊CPU分別作為源點和匯點,Ai是連線源點的容量,Bi是連線匯點的容量。

W連線兩塊需要共享資料的模組,建圖如上,求解S到T的最大流即為最小割。

試了一下Ford-Fulkerson 標號法求網路最大流……Orz可惜鄰接矩陣不能開得太大,一直MLE…果斷改Dinic!!

下面第一個AC對應的程式碼~

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <iomanip>
#include <algorithm>
#define max 21000
#define maxn 1000000
#define INF 0xfffffff
using namespace std;
struct edge
{
    int to,cap,rev;//終點、容量、反向邊
};
vector<edge>G[maxn];//圖的鄰接表表示
int level[maxn];//頂點到源點的距離標號
int iter[maxn];//當前弧,在其之前的邊都已經沒有用了
void add_edge(int from,int to,int cap)//向圖中增加一條從from到to的容量為cap的邊
{
    G[from].push_back((edge)
    {
        to,cap,G[to].size()
    });
    G[to].push_back((edge)
    {
        from,0,G[from].size()-1
    });
}
void bfs(int s)//通過BFS計算從源點出發的距離標號
{
    memset(level,-1,sizeof(level));
    queue<int>que;
    level[s]=0;
    que.push(s);
    while(!que.empty())
    {
        int v=que.front();
        que.pop();
        for(int i=0; i<G[v].size(); ++i)
        {
            edge &e=G[v][i];
            if(e.cap>0&&level[e.to]<0)
            {
                level[e.to]=level[v]+1;
                que.push(e.to);
            }
        }
    }
}
int dfs(int v,int t,int f)//DFS尋找增廣路
{
    if(v==t) return f;
    for(int &i=iter[v]; i<G[v].size(); ++i)
    {
        edge &e=G[v][i];
        if(e.cap>0&&level[v]<level[e.to])
        {
            int d=dfs(e.to,t,min(f,e.cap));
            if(d>0)
            {
                e.cap-=d;
                G[e.to][e.rev].cap+=d;
                return d;
            }
        }
    }
    return 0;
}
int Dinic(int s,int t)//求解s到t的最大流
{
    int maxflow=0;
    while(1)
    {
        bfs(s);
        if(level[t]<0) return maxflow;
        memset(iter,0,sizeof(iter));
        int f;
        while((f=dfs(s,t,INF))>0)
            maxflow+=f;
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int i,a,b,w;
    int n,m;
    cin>>n>>m;
    for(i=1; i<=n; ++i)
    {
        cin>>a>>b;
        add_edge(0,i,a);
        add_edge(i,n+1,b);
        add_edge(i,0,a);//雙向邊
        add_edge(n+1,i,b);
    }
    while(m--)
    {
        cin>>a>>b>>w;
        add_edge(a,b,w);
        add_edge(b,a,w);//雙向邊
    }
    cout<<Dinic(0,n+1)<<endl;
    return 0;
}
/*
3 1
1 10
2 10
10 3
2 3 1000
*/


② 

就是第二行AC對應的程式碼~

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <iomanip>
#include <algorithm>
#define nmax 21000
#define mmax 1000000
#define INF 0xfffffff
using namespace std;
struct Edge
{
    int u,v,cap,flow;
    int next;
    Edge(int a=0,int b=0,int c=0,int d=0):u(a),v(b),cap(c),flow(d) {}
};
struct Edgelist
{
    int start[nmax];
    int last[nmax];
    int t,i;
    Edge arc[mmax];
    void Clear()//清除
    {
        t=0;
        memset(last,-1,sizeof(last));
    }
    void Push_back(Edge edge)//追加
    {
        edge.next=-1;
        arc[t]=edge;
        if(last[edge.u]!=-1) arc[last[edge.u]].next=t;
        else start[edge.u]=t;
        last[edge.u]=t;
        ++t;
    }
    void add_arc(Edge edge//建立雙向弧
    {
        Push_back(edge);
        Push_back(Edge(edge.v,edge.u,edge.cap));
    }
} net;
int q[2][nmax];//陣列模擬滾動數列
int q1[2],q2[2],qnow;
void Push_queue(int a)//入佇列
{
    q[qnow][q2[qnow]++]=a;
}
int Pop_queue()//出佇列
{
    return q[qnow^1][q1[qnow^1]++];
}
void Switch_queue()//滾動佇列
{
    qnow^=1;
    q1[qnow]=0,q2[qnow]=0;
}
bool Empty_queue()//判空
{
    return q1[qnow^1]>=q2[qnow^1];
}
int Size_queue()//大小
{
    return q2[qnow^1]-q1[qnow^1];
}
int n,m;
int dis[nmax];//層次網路(距離標號)
int path[nmax],deep;//路徑
int cur[nmax];
bool BFS()//構建層次網路
{
    int i,l,u,v;
    memset(dis,-1,sizeof(dis));
    dis[0]=0;
    qnow=0;
    Switch_queue();
    Push_queue(0);
    Switch_queue();
    while(!Empty_queue())
    {
        l=Size_queue();
        while(l--)
        {
            u=Pop_queue();
            for(i=net.start[u]; i!=-1; i=net.arc[i].next)
            {
                v=net.arc[i].v;
                if(dis[v]==-1&&net.arc[i].cap>net.arc[i].flow)
                {
                    Push_queue(v);
                    dis[v]=dis[u]+1;
                    if(v==n) return true;
                }
            }
        }
        Switch_queue();
    }
    return false;
}
int Dinic()//求最大流
{
    int i,u,neck,pos,res;
    int maxflow=0;
    while(BFS())
    {
        memcpy(cur,net.start,sizeof(cur));
        deep=u=0;
        while(1)//最短路增廣
        {
            if(u==n)//存在增廣路則修改殘餘網路
            {
                neck=INF;
                for(i=0; i<deep; ++i)
                {
                    res=net.arc[path[i]].cap-net.arc[path[i]].flow;
                    if(res<neck)
                    {
                        neck=res;
                        pos=i;
                    }
                }
                maxflow+=neck;
                for(i=0; i<deep; ++i)
                {
                    net.arc[path[i]].flow+=neck;
                    net.arc[path[i]^1].flow-=neck;
                }
                deep=pos;
                u=net.arc[path[deep]].u;
            }
            for(i=cur[u]; i!=-1; i=net.arc[i].next)//在層次網路中進行增廣
            {
                if(net.arc[i].cap>net.arc[i].flow&&dis[u]+1==dis[net.arc[i].v])
                    break;
            }
            cur[u]=i;
            if(i!=-1)
            {
                path[deep++]=i;
                u=net.arc[i].v;
            }
            else
            {
                if(deep==0) break;
                dis[u]=-1;
                u=net.arc[path[--deep]].u;
            }
        }
    }
    return maxflow;//最大流
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int i,a,b,w;
    cin>>n>>m;
    net.Clear();
    for(i=1; i<=n; ++i)//插入弧
    {
        cin>>a>>b;
        net.add_arc(Edge(0,i,a));
        net.add_arc(Edge(i,n+1,b));
    }
    while(m--)
    {
        cin>>a>>b>>w;
        net.add_arc(Edge(a,b,w));
    }
    ++n;
    cout<<Dinic()<<endl;
    return 0;
}
/*
3 1
1 10
2 10
10 3
2 3 1000
*/



相關文章