1. 程式人生 > >POJ 3469 Dual Core CPU (最大流最小割經典題)

POJ 3469 Dual Core CPU (最大流最小割經典題)

Dual Core CPU
Time Limit: 15000MS Memory Limit: 131072K
Total Submissions: 24781 Accepted: 10732
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

題意:給你n個CPU,每個CPU都有兩種mode,而且每個CPU只能選擇一種mode執行,然後給你m個限制條件,a,b,c,如果a和b兩個cpu用的不是一種mode,就需要c個花費來彌補這個問題,問每個CPU都執行的最小花費。

思路:大家都說看到兩個集合一般就是最小割,記筆記記筆記(網路流還是要多刷題啊

1、經典的最小割模型。建圖如下:

①建立源點S,將其連入各個CPU,權值設定為Ai。

②建立匯點T,將各個CPU連入匯點,權值設定為Bi。

③對於m個限制,(a,b,c),將a連入b,權值設定為c,將b連入a,權值設定也是c。

2、那麼為什麼對於m個限制這樣建圖就能夠達到目的選取最小割呢?

我們來看幾個圖:

①假設我們現在m==0


那麼很明顯,我們的最大流==最小割==2+3=5,同時也就是最小花費。跑得的殘餘網路:

1、經典的最小割模型。建圖如下:

①建立源點S,將其連入各個CPU,權值設定為Ai。

②建立匯點T,將各個CPU連入匯點,權值設定為Bi。

③對於m個限制,(a,b,c),將a連入b,權值設定為c,將b連入a,權值設定也是c。

2、那麼為什麼對於m個限制這樣建圖就能夠達到目的選取最小割呢?

我們來看幾個圖:

①假設我們現在m==0


那麼很明顯,我們的最大流==最小割==2+3=5,同時也就是最小花費。跑得的殘餘網路:



通過上面兩個圖(轉自:mengxiang000), 我們會發現, 如果沒有限制條件, 那肯定就是最小割,每個點只能屬於一個集合, 最小割就是最優值, 它要求不在同一個陣營選會有額外話費, 那就在這兩個點連一個無向邊,你會發現要斷開這兩個集合,如果斷開不是一個集合的邊的話,必須要斷開中間的某條線跟左右集合裡的一條邊~

程式碼:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cmath>
#include <vector>
using namespace std;
const int maxn = 120050;
const int maxv = 200005;
const int INF = 0x3f3f3f3f;
int head[maxn], cur[maxn], d[maxn], n, m, s, t, k, sum;
struct node
{
    int v, w, next;
}edge[3000005];
void addEdge(int u, int v, int w)
{
    edge[k].v = v;
    edge[k].w = w;
    edge[k].next = head[u];
    head[u] = k++;
    edge[k].v = u;
    edge[k].w = 0;
    edge[k].next = head[v];
    head[v] = k++;

}
int bfs()
{
    memset(d, 0, sizeof(d));
    d[s] = 1;
    queue<int> q;
    q.push(s);
    while(!q.empty())
    {
        int u = q.front();
        if(u == t) return 1;
        q.pop();
        for(int i = head[u]; i != -1; i = edge[i].next)
        {
            int to = edge[i].v, w = edge[i].w;
            if(w && d[to] == 0)
            {
                d[to] = d[u] + 1;
                if(to == t) return 1;
                q.push(to);
            }
        }
    }
    return 0;
}
int dfs(int u, int maxflow)
{
    if(u == t) return maxflow;
    int ret = 0;
    for(int i = cur[u]; i != -1; i = edge[i].next)
    {
        int to = edge[i].v, w = edge[i].w;
        if(w && d[to] == d[u]+1)
        {
            int f = dfs(to, min(maxflow-ret, w));
            edge[i].w -= f;
            edge[i^1].w += f;
            ret += f;
            if(ret == maxflow) return ret;
        }
    }
    return ret;
}
int Dinic()
{
    int ans = 0;
    while(bfs())
    {
        memcpy(cur, head, sizeof(head));
        ans += dfs(s, INF);
    }
    return ans;
}
int main()
{
    while(~scanf("%d%d", &n, &m))
    {
        s = 0, t = n+1, k = 0;
        memset(head, -1, sizeof(head));
        int x, y, z;
        for(int i = 1; i <= n; i++)
        {
            scanf("%d%d", &x, &y);
            addEdge(s, i, x);
            addEdge(i, t, y);
        }
        for(int i = 1; i <= m; i++)
        {
            scanf("%d%d%d", &x, &y, &z);
            addEdge(x, y, z);
            addEdge(y, x, z);
        }
        printf("%d\n", Dinic());
    }
    return 0;
}


1、經典的最小割模型。建圖如下:

①建立源點S,將其連入各個CPU,權值設定為Ai。

②建立匯點T,將各個CPU連入匯點,權值設定為Bi。

③對於m個限制,(a,b,c),將a連入b,權值設定為c,將b連入a,權值設定也是c。

2、那麼為什麼對於m個限制這樣建圖就能夠達到目的選取最小割呢?

我們來看幾個圖:

①假設我們現在m==0


那麼很明顯,我們的最大流==最小割==2+3=5,同時也就是最小花費。跑得的殘餘網路: