zoukankan      html  css  js  c++  java
  • JOJ 2453 Candy

    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;    
    }
  • 相关阅读:
    配置 Sublime Text 用 Node.js 执行 JavaScript 程序
    KNN算法
    堆排序(heap sort)
    复原二叉树
    二叉树的广度优先遍历(层次遍历)
    二叉树(BT)相关
    BST(二叉搜索树)相关
    二叉树遍历(先序、中序、后序)
    排序算法
    查找算法
  • 原文地址:https://www.cnblogs.com/staginner/p/2625600.html
Copyright © 2011-2022 走看看