題意: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;
}