zoukankan      html  css  js  c++  java
  • BZOJ 2245: [SDOI2011]工作安排( 费用流 )

     

    费用流模板题..限制一下不同愤怒值的工作数就可以了。

    ---------------------------------------------------------------------------------------------

    #include<queue>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
     
    using namespace std;
     
    typedef long long ll;
     
    const int maxn = 259;
    const int INF = 1000000000;
     
    int m, n, t[maxn], w[maxn];
    int S, T, V, d[maxn << 1], a[maxn << 1];
    bool inq[maxn << 1];
    deque<int> q;
     
    struct edge {
    int t, c, w;
    edge *n, *r;
    } E[maxn * maxn << 1], *pt = E, *H[maxn << 1], *p[maxn << 1];
     
    inline void Add(int u, int v, int c, int w) {
    pt->t = v, pt->c = c, pt->w = w, pt->n = H[u], H[u] = pt++;
    }
    inline void AddEdge(int u, int v, int c, int w) {
    Add(u, v, c, w), Add(v, u, 0, -w);
    H[u]->r = H[v], H[v]->r = H[u];
    }
     
    void Work() {
    ll ans = 0;
    for(; ; ) {
    for(int i = 0; i < V; i++)
    d[i] = INF, inq[i] = false;
    q.push_front(S);
    d[S] = 0, a[S] = INF;
    while(!q.empty()) {
    int x = q.front(); q.pop_front();
    inq[x] = false;
    for(edge* e = H[x]; e; e = e->n) if(d[e->t] > d[x] + e->w && e->c) {
    d[e->t] = d[x] + e->w;
    a[e->t] = min(a[x], e->c);
    p[e->t] = e;
    if(inq[e->t]) continue;
    inq[e->t] = true;
    if(!q.empty() && d[q.front()] > d[e->t]) {
    q.push_front(e->t);
    } else
    q.push_back(e->t);
    }
    }
    if(d[T] == INF) break;
    ans += ll(a[T]) * d[T];
    for(int x = T; x != S; x = p[x]->r->t)
    p[x]->c -= a[T], p[x]->r->c += a[T];
    }
    printf("%lld ", ans);
    }
     
    int main() {
    scanf("%d%d", &m, &n);
    S = m + n, T = S + 1, V = T + 1;
    for(int i = 0; i < n; i++) {
    int t;
    scanf("%d", &t);
    AddEdge(i, T, t, 0);
    }
    for(int i = 0; i < m; i++)
    for(int j = 0; j < n; j++) {
    int t;
    scanf("%d", &t);
    if(t) AddEdge(i + n, j, INF, 0);
    }
    t[0] = 0;
    for(int i = 0; i < m; i++) {
    int s, v = i + n;
    scanf("%d", &s);
    for(int j = 1; j <= s; j++) scanf("%d", t + j);
    for(int j = 0; j <= s; j++) scanf("%d", w + j);
    for(int j = 1; j <= s; j++)
    AddEdge(S, v, t[j] - t[j - 1], w[j - 1]);
    AddEdge(S, v, INF, w[s]);
    }
    Work();
    return 0;
    }

    ---------------------------------------------------------------------------------------------

    2245: [SDOI2011]工作安排

    Time Limit: 20 Sec  Memory Limit: 512 MB
    Submit: 1245  Solved: 608
    [Submit][Status][Discuss]

    Description

    你的公司接到了一批订单。订单要求你的公司提供n类产品,产品被编号为1~n,其中第i类产品共需要Ci件。公司共有m名员工,员工被编号为1~m员工能够制造的产品种类有所区别。一件产品必须完整地由一名员工制造,不可以由某名员工制造一部分配件后,再转交给另外一名员工继续进行制造。

    我们用一个由01组成的m*n的矩阵A来描述每名员工能够制造哪些产品。矩阵的行和列分别被编号为1~m1~nAi,j1表示员工i能够制造产品j,为0表示员工i不能制造产品j

    如果公司分配了过多工作给一名员工,这名员工会变得不高兴。我们用愤怒值来描述某名员工的心情状态。愤怒值越高,表示这名员工心情越不爽,愤怒值越低,表示这名员工心情越愉快。员工的愤怒值与他被安排制造的产品数量存在某函数关系,鉴于员工们的承受能力不同,不同员工之间的函数关系也是有所区别的。

    对于员工i,他的愤怒值与产品数量之间的函数是一个Si+1段的分段函数。当他制造第1~Ti,1件产品时,每件产品会使他的愤怒值增加Wi,1,当他制造第Ti,1+1~Ti,2件产品时,每件产品会使他的愤怒值增加Wi,2……为描述方便,设Ti,0=0,Ti,si+1=+,那么当他制造第Ti,j-1+1~Ti,j件产品时,每件产品会使他的愤怒值增加Wi,j 1jSi+1

    你的任务是制定出一个产品的分配方案,使得订单条件被满足,并且所有员工的愤怒值之和最小。由于我们并不想使用Special Judge,也为了使选手有更多的时间研究其他两道题目,你只需要输出最小的愤怒值之和就可以了。

    Input

    第一行包含两个正整数mn,分别表示员工数量和产品的种类数;

    第二行包含个正整数,第i个正整数为Ci

    以下m行每行个整数描述矩阵A

    下面m个部分,第i部分描述员工i的愤怒值与产品数量的函数关系。每一部分由三行组成:第一行为一个非负整数Si,第二行包含Si个正整数,其中第j个正整数为Ti,j,如果Si=0那么输入将不会留空行(即这一部分只由两行组成)。第三行包含Si+1个正整数,其中第j个正整数为Wi,j

    Output

    仅输出一个整数,表示最小的愤怒值之和。

    Sample Input


    2 3

    2 2 2

    1 1 0

    0 0 1

    1

    2

    1 10

    1

    2

    1 6

    Sample Output

    24

    HINT

    Source

  • 相关阅读:
    14.6 将运算分组为事务
    Android 取得 ListView中每个Item项目的值
    【编程题目】n 个骰子的点数
    【编程题目】扑克牌的顺子
    【编程题目】颠倒栈☆
    【编程题目】输出 1 到最大的 N 位数
    【编程题目】寻找丑数
    【编程题目】在字符串中删除特定的字符
    【编程题目】复杂链表的复制☆
    【编程题目】找出数组中两个只出现一次的数字 ★★(自己没做出来)
  • 原文地址:https://www.cnblogs.com/JSZX11556/p/5172960.html
Copyright © 2011-2022 走看看