ProblemDescription
There are Ncandies and M kids, the teacher will give this N candies to the M kids. Thei-th kids for the j-th candy has a preference for like[i][j], if he like thesugar, like[i][j] = 1, otherwise like[i][j] = 0. If the i-th kids get the candywhich he like he will get K glad value. If he or she do not like it. He willget only one glad value. We know that the i-th kids will feel happy if he thesum of glad values is equal or greater than B[i]. Can you tell me whetherreasonable allocate this N candies, make every kid feel happy.
Input
The Input consistsof several cases .The first line contains a single integer t .the number oftest cases.
For each case starts with a line containing three integers N, M, K(1<=N<=13, 1<=M<=13, 2<=K<=10)
The next line contains M numbers which is B[i](0<=B[i]<=1000). Separatedby a single space.
Then there are M*N like[i][j] , if the i-th kids like the j-th sugarlike[i][j]=1 ,or like[i][j]=0.
Output
If there have areasonable allocate make every kid feel happy, output "YES", or"NO".
Sample Input
2
3 2 2
2 2
0 0 0
0 0 1
3 2 2
2 2
0 0 0
0 0 0
Sample Output
Case #1: YES
Case #2: NO
集训期间,实在太累,不写了。。。。。。待到开学再来慢慢写吧
#include <iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>>
#define INF 1000000000
using namespace std;
const int M = 4 * 10010;//边
struct Node//边,点f到点t,流量为c,费用为w
{
int st, ed;
int flow, cost;
int next;
}edge[M];
int head[M], dis[M], q[M], pre[M], cnt;//cnt为已添加的边数,head为邻接表,dis为花费,pre为父亲节点
bool vis[M];
int b[15] ,like[15][15];
int n, m, k;
void init()
{
memset(head, -1, sizeof(head));
cnt = 0;
}
void add_edge(int f, int t, int d1, int d2, int w)
{//f到t的一条边,流量为d1,反向流量d2,花费w,反向边花费-w(可以反悔)
edge[cnt].st = f;
edge[cnt].ed = t;
edge[cnt].flow = d1;
edge[cnt].cost = w;
edge[cnt].next = head[f];
head[f] = cnt++;
edge[cnt].st = t;
edge[cnt].ed = f;
edge[cnt].flow = d2;
edge[cnt].cost = -w;
edge[cnt].next = head[t];
head[t] = cnt++;
}
bool spfa(int s, int t, int n)
{
int i, tmp, l, r;
memset(pre, -1, sizeof(pre));
for(i = 0; i < n; ++i)
{
dis[i] = INF;
}
dis[s] = 0;
q[0] = s;
l = 0, r = 1;
vis[s] = true;
while(l != r)
{
tmp = q[l];
l = (l + 1) % (n + 1);
vis[tmp] = false;
for(i = head[tmp]; i!=-1; i = edge[i].next)
{
if(edge[i].flow && dis[edge[i].ed] > dis[tmp] + edge[i].cost)
{
dis[edge[i].ed] = dis[tmp] + edge[i].cost;
pre[edge[i].ed] = i;
if(!vis[edge[i].ed])
{
vis[edge[i].ed] = true;
q[r] = edge[i].ed;
r = (r + 1) % (n + 1);
}
}
}
}
if(pre[t] == -1)
{
return false;
}
return true;
}
void MCMF(int s, int t, int n, int &flow, int &cost)
{//起点s,终点t,点数n,最大流flow,最小花费cost
int tmp, arg;
flow = cost = 0;
while(spfa(s, t, n))
{
arg = INF;
tmp = t;
while(tmp != s)
{
arg = min(arg, edge[pre[tmp]].flow);
tmp = edge[pre[tmp]].st;
}
tmp = t;
while(tmp != s)
{
edge[pre[tmp]].flow -= arg;
edge[pre[tmp] ^ 1].flow += arg;
tmp = edge[pre[tmp]].st;
}
flow += arg;
cost += arg * dis[t];
}
}
int main()
{
int t ,no ,num[15] ,flag[15];
int flow ,cost ,sum;
scanf("%d",&t);
for(int r = 1;r<=t;r++)
{
memset(flag,0,sizeof(flag));
memset(num,0,sizeof(num));
sum = 0;
scanf("%d%d%d",&n,&m,&k);
for(int i = 1;i<=m;i++)
{
scanf("%d",&b[i]);
sum += b[i];
}
no = 1;
for(int i = 1;i<=m;i++)
{
for(int j = 1;j<=n;j++)
{
scanf("%d",&like[i][j]);
if(like[i][j] && !flag[j])
{
num[j] = no++;
}
}
}
init();
no = m + no - 1;
for(int i = 1;i<=m;i++)
{
add_edge(0,i,b[i]/k,0,-k);
if(b[i] % k)
{
no++;
add_edge(0,no,1,0,-(b[i] % k));
}
for(int j = 1;j<=n;j++)
{
if(like[i][j])
{
add_edge(i,m + num[j],1,0,0);
if(b[i] % k)
{
add_edge(no,m + num[j],1,0,0);
}
}
}
}
no++;
for(int i = 1;i<=n;i++)
{
if(num[i])
{
add_edge(m + num[i],no,1,0,0);
}
}
MCMF(0,no,no + 1,flow,cost);
if(sum + cost > n - flow)
{
printf("Case #%d: NO\n",r);
}
else
{
printf("Case #%d: YES\n",r);
}
}
return 0;
}