zoukankan      html  css  js  c++  java
  • BASHU 2445 餐巾问题

    BASHU_2445

        题目链接:http://mail.bashu.cn:8080/bs_oj/showproblem?problem_id=2445

        很好的一个题目,让我又加深了对最小费用最大流的问题。一开始自己“意淫”了一个最小费用流的图,结果样例一直算的是180,后来才发现自己还是没有理解好最小费用最大流的含义,所谓的“最小费用最大流”,首要保证的条件是最大流,如果最优的情况未必是原图达到“最大流”时的情况的话,那么是不能用“最小费用最大流”算法去解决的。

        那么既然上面yy出了问题,不妨就先着手解决这个问题:要将“最大流”赋予怎样的含义(也就是说确定是什么东西达到“最大”)才能保证最优情况是原图达到“最大流”时的情况呢?一种可行的思路就是确定每天使用的餐巾的数量达到“最大”,不管是用的旧的还是新买的,反正总要用那么多,这样最优情况一定是满足“最大流”条件的。那么我们就要继续考虑这些使用的东西是从哪里来的,一部分是新买的,另一部分是用剩下的洗了之后的,新买的好办,直接建个源点流出来费用为P的流即可,那么洗了之后的那部分是怎么来的?肯定首先要满足是剩下的,那么怎么才会剩下呢?每天用了多少就会剩下多少。想到这,其实大部分问题已经解决了,剩下的就是考虑脏的餐巾存放及清洗的问题了,这部分放到建图里一起说吧。

        接下来我们考虑建图,首先将一个点i拆成两个点i和i',一共要建六类边:

        ① (S,i,n,P) :S到i的容量为n(n表示当天需要的餐巾的数量)费用为P的边,表示今天最多买n条新的餐巾,当然把容量搞成INF也无所谓。

        ② (i,T,n,0) :i到T的容量为n费用为0的边,表示今天最多用n条餐巾,通过这样的边保证了每天的最大流都是所需餐巾的数量。

        ③ (S,i',n,0) :S到i'的容量为n费用为0的边,表示今天会剩下n条餐巾,之所以费用为0是因为这些是剩下的,之前肯定已经买过了,所以费用是0。这里的容量就不能搞成INF了,一个原因是因为最后一定至多只会生剩下n条,另一个原因就是这里如果搞成INF会造成错误,因为会凭空多了好多用过的餐巾,而这些餐巾是没有被买过的。

        ④ (i',i+xn,INF,xw) :i'到i+xn(xn表示快洗部洗一条餐巾所需的天数)的容量为INF费用为xw(xw表示快洗部洗一条餐巾所需的费用)的边,表示累计到今天的剩下的部分或者全部的餐巾可以放到快洗部去洗,并由第i+xn天使用。

        ⑤ (i',i+yn,INF,yw) :和上面那类边基本一样,只不过现在是慢洗部了。

        ⑥ (i',(i+1)',INF,0) : i'到(i+1)'的容量为INF费用为0的边,表示第i天用脏了的餐巾可以积攒到第i+1天再做打算。

        建完上面的边之后做最小费用最大流就可以了。

    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #define MAXD 2010
    #define MAXM 12010
    #define INF 0x3f3f3f3f
    int N, P, xn, xw, yn, yw, first[MAXD], e, next[MAXM], v[MAXM], flow[MAXM], cost[MAXM];
    int S, T, q[MAXD], inq[MAXD], pre[MAXD], dis[MAXD];
    const int Q = 2005;
    void add(int x, int y, int f, int c)
    {
        v[e] = y, flow[e] = f, cost[e] = c;
        next[e] = first[x], first[x] = e ++;
    }
    void init()
    {
        int i, j, n;
        S = 0, T = N * 2 + 1;
        memset(first, -1, sizeof(first[0]) * (T + 1)), e = 0;
        for(i = 1; i <= N; i ++)
        {
            scanf("%d", &n);
            add(S, i, n, P), add(i, S, 0, -P);
            add(i, T, n, 0), add(T, i, 0, 0);
            add(S, i + N, n, 0), add(i + N, S, 0, 0);
            if(i + xn <= N)
                add(i + N, i + xn, INF, xw), add(i + xn, i + N, 0, -xw);
            if(i + yn <= N)
                add(i + N, i + yn, INF, yw), add(i + yn, i + N, 0, -yw);
            if(i < N)
                add(i + N, i + 1 + N, INF, 0), add(i + 1 + N, i + N, 0, 0);
        }
    }
    int bfs()
    {
        int i, x, front = 0, rear = 0;
        memset(dis, 0x3f, sizeof(dis[0]) * (T + 1));
        dis[S] = 0, pre[S] = -1, q[rear ++] = S;
        memset(inq, 0, sizeof(inq[0]) * (T + 1));
        while(front != rear)
        {
            x = q[front ++], inq[x] = 0;
            front > Q ? front = 0 : 0;
            for(i = first[x]; i != -1; i = next[i])
                if(flow[i] && dis[v[i]] > dis[x] + cost[i])
                {
                    dis[v[i]] = dis[x] + cost[i], pre[v[i]] = i;
                    if(!inq[v[i]])
                    {
                        q[rear ++] = v[i], inq[v[i]] = 1;
                        rear > Q ? rear = 0 : 0;
                    }
                }
        }
        return dis[T] != INF;
    }
    void solve()
    {
        int i, a, c = 0;
        while(bfs())
        {
            for(i = pre[T], a = INF; i != -1; i = pre[v[i ^ 1]]) a = std::min(a, flow[i]);
            for(i = pre[T]; i != -1; i = pre[v[i ^ 1]])
                flow[i] -= a, flow[i ^ 1] += a;
            c += a * dis[T];    
        }
        printf("%d\n", c);
    }
    int main()
    {
        while(scanf("%d%d%d%d%d%d", &N, &P, &xn, &xw, &yn, &yw) == 6)
        {
            init();
            solve();    
        }
        return 0;    
    }
  • 相关阅读:
    一种针对SOA的消息类型架构
    许可方式 到底"非商业用途"意味着什么?
    Windows 7的CMD中 Telnet 无法执行的解决办法
    ASP.NET MVC 2.0 中文正式版发布
    什么是REST?
    架构、框架的区别
    Firefox 火狐下自动刷新的插件 ReloadEvery
    ASP.NET与JQUERY的AJAX文件上传 视频课件+源码Demo
    给吸烟的园友们:一个被烟草行业隐瞒了十年的秘密,烟真不是人吸的
    Echo Server,AsyncSocket,SocketAsyncEvent,SocketAsyncEventArgs,AsyncQueue
  • 原文地址:https://www.cnblogs.com/staginner/p/2642239.html
Copyright © 2011-2022 走看看