您的位置:首页 > 其它

JOJ 2453 Candy

2012-08-06 18:26 288 查看
JOJ_2453

假如最后剩下的是价值为1的若干颗糖,显然这些糖分给谁都是无所谓的,因此我们不妨先考虑如何分配最终价值为2的这些糖,这样剩下的只能是价值为1的糖再按需分配,即谁还少就给谁就行了。而且我们在分配价值为2的糖的时候,第i个人得到的总价值不应大于B[i],因为这样相当于浪费了糖,即便B[i]为奇数也是一样的。但是如果将糖的价值视作2,这样是没办法做网络流的,因为容量为2的边有可能只流满了一半,于是不妨将价值为2的糖看作价值为1,将B[i]看作B[i]/2,然后将源点连各个人,容量为B[i]/2,再将人连上相对于自己而言价值为2的糖,容量为INF,最后将各个糖和汇点相连,容量为1。这样做完最大流就可以得到最多分配了多少价值为2的糖,再根据剩下了多少价值为1的糖就可以判断最后能否满足每一个人了。

但是这样有个致命的问题就是糖太多了,必然会超时,因此我们要想办法减小糖的规模。由于人数很少,这样就可以根据每颗糖被喜欢的情况将糖划分成不超过1024类,这样图的总点数就比较少了。

#include<stdio.h>
#include<string.h>
#define MAXN 1500
#define MAXM 15
#define MAXE 33000
#define INF 0x3f3f3f3f
int N, M, S, T, h[1030];
int first[MAXN], e, next[MAXE], v[MAXE], flow[MAXE];
int d[MAXN], work[MAXN], q[MAXN];
long long SUM;
void add(int x, int y, int z)
{
v[e] = y, flow[e] = z;
next[e] = first[x], first[x] = e ++;
}
void init()
{
int i, j, k, a, b, cnt;
scanf("%d%d", &N, &M);
memset(first, -1, sizeof(first));
memset(h, 0, sizeof(h));
e = cnt = 0;
for(i = 1; i <= N; i ++)
{
a = 0;
for(j = 1; j <= M; j ++)
{
scanf("%d", &k);
a = a << 1 | (k == 2);
}
if(!h[a]) ++ cnt;
++ h[a];
}
S = 0, T = cnt + M + 1;
cnt = 0;
for(i = 1; i < 1024; i ++)
if(h[i])
{
++ cnt;
for(j = 1; j <= M; j ++)
if(i & 1 << (M - j))
add(j, cnt + M, INF), add(cnt + M, j, 0);
add(cnt + M, T, h[i]), add(T, cnt + M, 0);
}
SUM = 0;
for(i = 1; i <= M; i ++)
{
scanf("%d", &b), SUM += b;
if(b > 1)
add(S, i, b >> 1), add(i, S, 0);
}
}
int bfs()
{
int i, j, rear = 0;
memset(d, -1, sizeof(d[0]) * (T + 1));
d[S] = 0, q[rear ++] = S;
for(i = 0; i < rear; i ++)
for(j = first[q[i]]; j != -1; j = next[j])
if(flow[j] && d[v[j]] == -1)
{
d[v[j]] = d[q[i]] + 1, q[rear ++] = v[j];
if(v[j] == T)
return 1;
}
return 0;
}
int dfs(int cur, int a)
{
if(cur == T)
return a;
int t;
for(int &i = work[cur]; i != -1; i = next[i])
if(flow[i] && d[v[i]] == d[cur] + 1)
if(t = dfs(v[i], a < flow[i] ? a : flow[i]))
{
flow[i] -= t, flow[i ^ 1] += t;
return t;
}
return 0;
}
int dinic()
{
int ans = 0, t;
while(bfs())
{
memcpy(work, first, sizeof(first[0]) * (T + 1));
while(t = dfs(S, INF))
ans += t;
}
return ans;
}
void solve()
{
if(SUM > N * 2)
{
printf("No\n");
return ;
}
if(SUM <= N)
{
printf("Yes\n");
return ;
}
printf("%s\n", SUM <= N + dinic() ? "Yes" : "No");
}
int main()
{
int t;
scanf("%d", &t);
while(t --)
{
init();
solve();
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: