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;
}


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