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;    
}
posted on 2012-08-06 18:26  Staginner  阅读(426)  评论(0编辑  收藏  举报