hdu - 4322 - Candy - 網絡流

題意:http://acm.hdu.edu.cn/showproblem.php?pid=4322

   like[i][j]表示第i個孩子喜歡第j個糖果(總共m個孩子,n個糖)。 如果孩子拿到他喜歡的糖果,那麼他將會增加k個歡樂值;拿到不喜歡的,增加1。 如果孩子i的歡樂值大於B[i],那麼他纔是開心的。

  問,能否有一種分配方案,讓所有孩子都開心。

解:

首先聲明,由於被小孩子不喜歡的糖果的對小孩產生的效力是一樣的,所以我們在網絡流的時候先不考慮。

1 - 源點0到1~N個糖果,容量爲1,費用爲0

2 - 根據like數組,like[i][j] == 1時在糖果j和人N+i之間建立有一條邊,容量爲1,費用爲0

3*- 根據b[i]和K的值建立小孩和匯點之間的邊:

如果b[i] 是 K 的倍數, 說明花費b[i] / K個喜歡的糖果可以達到b[i],建立一條邊,費用爲K,容量爲b[i] / K;

否則,將這條邊拆爲兩部分,第一部分是b[i] / K的部分,第二部分根據b[i] % K的部分。(如果b[i] % k == 0,說明b[i]是k的倍數;

若b[i] % k == 1, 特殊糖果和一般糖果價值一樣,沒必要當做特殊糖果處理)

建好圖後,求最大費用最大流(只需將費用改爲負的,然後套最小費用最大流即可).。得出特殊糖果匹配b[i]的最大值。看剩餘的普通糖果是否滿足缺少的b[i]。

#include <cstring>
#include <cstdio>
const int maxn = 100;
const int maxm = maxn * maxn * 2;
const int inf = 1000000000;

int n, m, k;
int b[maxn], sumB;
int c[maxn][maxn];
int src, des;

struct Edge{
    int u, v, w, f, nxt;
}edge[maxm];
int edgeNum, head[maxn];

inline void initEdge(){
    edgeNum = 0;
    memset(head, - 1, sizeof(head));
}

inline void addEdgeSub(int u, int v, int w, int f){
    edge[edgeNum].u = u;
    edge[edgeNum].v = v;
    edge[edgeNum].w = w;
    edge[edgeNum].f = f;
    edge[edgeNum].nxt = head[u];
    head[u] = edgeNum ++;
}

inline void addEdge(int u, int v, int w, int f){
    addEdgeSub(u,v,w,f);
    addEdgeSub(v,u,-w,0);
}

void buildGraph(){
    initEdge();
    src = 0;
    des = n + m + 1;
    for(int i = 0; i < n; i ++){
        addEdge(src, i + 1, 0, 1);
    }
    for(int i = 0; i < m; i ++){
        for(int j = 0; j < n; j ++){
            if(c[i][j]){
                addEdge(j + 1, i + n + 1,0,1);//
            }
        }
        addEdge(i + n + 1, des, k, b[i] / k);
        if(b[i] % k > 1){
            addEdge(i + n + 1, des, b[i] % k, 1);
        }
    }
}

int dis[maxn];
int queue[maxn];
bool vis[maxn];
int back[maxn];

bool bfs(){
    int front = 0, rear = 1;
    memset(vis, false, sizeof(vis));
    memset(dis, -1, sizeof(dis));
    queue[0] = src;
    dis[src] = 0;
    vis[src] = true;
    back[src] = -1;
    bool flag = false;
    while(front != rear){
        int u = queue[front];
        for(int i = head[u]; i != -1; i = edge[i].nxt){
            int v = edge[i].v;
            int w = edge[i].w;
            if(edge[i].f){
                if(dis[v] < dis[u] + w){
                    dis[v] = dis[u] + w;
                    back[v] = i;
                    if(!vis[v]){
                        vis[v] = true;
                        queue[rear] = v;
                        if(++ rear >= maxn){
                            rear = 0;
                        }
                    }
                }
            }
        }
        vis[u] = false;
        if(++ front >=  maxn){
            front = 0;
        }
    }
    return dis[des] != -1;
}

int getFlow(){
    int tmp = des;
    int Min = inf;
    while(back[tmp] != -1){
        if(edge[back[tmp]].f < Min){
            Min = edge[back[tmp]].f;
        }
        tmp = edge[back[tmp]].u;
    }
    tmp = des;
    while(back[tmp] != -1){
        edge[back[tmp]].f -= Min;
        edge[back[tmp] ^ 1].f += Min;
        tmp = edge[back[tmp]].u;
    }
    return Min;
}

bool judge(){
    int cost = 0, flow = 0;
    while(bfs()){
        cost += dis[des];
        flow += getFlow();
    }
    return n - flow >= sumB - cost;
}

int main(){
    int T;
    scanf("%d",&T);
    for(int ca = 1; ca <= T; ca ++){
        scanf("%d%d%d",&n,&m,&k);
        sumB = 0;
        for(int i = 0; i < m; i ++){
            scanf("%d",&b [i]);
            sumB += b[i];
        }
        for(int i = 0; i < m; i ++){
            for(int j = 0; j < n; j ++){
                scanf("%d",&c[i][j]);
            }
        }
        buildGraph();
        printf("Case #%d: ",ca);
        if(judge())
            puts("YES");
        else
            puts("NO");
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章