zoukankan      html  css  js  c++  java
  • HDU 5644 King's Pilots 费用流

    King's Pilots

    题目连接:

    http://acm.hdu.edu.cn/showproblem.php?pid=5644

    Description

    The military parade will last for n days. There is a aerobatic flight shows everyday during the parade. On the ith day , Pi pilots are required. But the pilots are not willing to work continually without an extra salary for even two days , because they are extremely tired.

    There are m Holiday formulations in this country. For each formulation j , that is: when a pilot works on a day , if you pay him Sj dollars he is willing to come back Tj days after that day.

    For example , If a pilot work on the rth day , and Tj==1 then he will return to work on r+1th day

    At the very beginning there are k pilots , but of course you can hire more pilots. However , training new pilots require P days and for each new pilot you need pay him Q dollars. (Which means you can only use new pilots on Pth day or later)

    Now our great king needs you to plan all these things. There must be enough pilots everyday and the cost must be minimized. Please tell the king what is the lowest cost;

    The N - 1 round, the next person of the person who is out in the last round counts off, and the person who report number n−1 is out.

    And the last man is survivor. Do you know the label of the survivor?

    Input

    The first line contains a number T(T≤5), the number of testcases.

    For each testcase, the first line contains a number n(n≤200)

    On the second line , there are n numbers Pi(1≤i≤n) indicating the number of pilots needed on that day

    On the third line , 3 numbers , m(1≤m≤5),P,Q

    On the following m lines , each line has two numbers: Si , Ti

    all input data x satisfy x∈[0,200]

    Output

    For each testcase, print a single number. The minimum cost.

    If there is no solution , just put No solution

    Sample Input

    1
    5 10
    1 3 5 10 6
    1 3 5
    2 2

    Sample Output

    48

    Hint

    题意

    有n天,每天需要p[i]个人,你一开始雇佣了k个人

    你从第p天开始可以再花Q元雇佣一个人。

    然后这些人只会工作一天。

    但是有m种政策,可以使得这些人在休息t[i]天后只用花s[i]元就可以再让这些工人工作了。

    题解:

    费用流。

    建图的话建两层。

    第一层假装没有那m种政策,然后无脑建图就好了。

    S向1连容量为k,花费为0的边。

    每个点向T连容量为P[i],花费为0的边。

    每个点i向i+1连容量为inf,花费为0的边。

    然后P天后的,连容量为inf,花费为q的边。

    第二层连政策。

    S向每个点连容量为P[i],花费为0的边。

    每个点向T[i]天后的第一层的点连容量为inf,花费为S[i]

    每个点i向i+1连容量为inf,花费为0的边。

    一层维护工作,一层维护政策。

    然后check是否满流就好了。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    const int MAXN = 10000;
    const int MAXM = 100000;
    const int INF = 0x3f3f3f3f;
    struct Edge
    {
        int to, next, cap, flow, cost;
        int x, y;
    } edge[MAXM],HH[MAXN],MM[MAXN];
    int head[MAXN],tol;
    int pre[MAXN],dis[MAXN];
    bool vis[MAXN];
    int N, M;
    char map[MAXN][MAXN];
    void init()
    {
        N = MAXN;
        tol = 0;
        memset(head, -1, sizeof(head));
    }
    void addedge(int u, int v, int cap, int cost)//左端点,右端点,容量,花费
    {
        edge[tol]. to = v;
        edge[tol]. cap = cap;
        edge[tol]. cost = cost;
        edge[tol]. flow = 0;
        edge[tol]. next = head[u];
        head[u] = tol++;
        edge[tol]. to = u;
        edge[tol]. cap = 0;
        edge[tol]. cost = -cost;
        edge[tol]. flow = 0;
        edge[tol]. next = head[v];
        head[v] = tol++;
    }
    bool spfa(int s, int t)
    {
        queue<int>q;
        for(int i = 0; i < N; i++)
        {
            dis[i] = INF;
            vis[i] = false;
            pre[i] = -1;
        }
        dis[s] = 0;
        vis[s] = true;
        q.push(s);
        while(!q.empty())
        {
            int u = q.front();
            q.pop();
            vis[u] = false;
            for(int i = head[u]; i != -1; i = edge[i]. next)
            {
                int v = edge[i]. to;
                if(edge[i]. cap > edge[i]. flow &&
                        dis[v] > dis[u] + edge[i]. cost )
                {
                    dis[v] = dis[u] + edge[i]. cost;
                    pre[v] = i;
                    if(!vis[v])
                    {
                        vis[v] = true;
                        q.push(v);
                    }
                }
            }
        }
        if(pre[t] == -1) return false;
        else return true;
    }
    //返回的是最大流, cost存的是最小费用
    int minCostMaxflow(int s, int t, int &cost)
    {
        int flow = 0;
        cost = 0;
        while(spfa(s,t))
        {
            int Min = INF;
            for(int i = pre[t]; i != -1; i = pre[edge[i^1]. to])
            {
                if(Min > edge[i]. cap - edge[i]. flow)
                    Min = edge[i]. cap - edge[i]. flow;
            }
            for(int i = pre[t]; i != -1; i = pre[edge[i^1]. to])
            {
                edge[i]. flow += Min;
                edge[i^1]. flow -= Min;
                cost += edge[i]. cost * Min;
            }
            flow += Min;
        }
        return flow;
    }
    const int inf = 1e9;
    int P[205],p,q,S[205],T[205];
    void solve()
    {
        init();
        int m,n,k,sum=0;
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++)
            scanf("%d",&P[i]),sum+=P[i];
        scanf("%d%d%d",&m,&p,&q);
        for(int i=1;i<=m;i++)
            scanf("%d%d",&S[i],&T[i]);
        int st=5000,ed=5001;
        for(int i=1;i<=n;i++)
        {
            addedge(st,i,P[i],0);
            addedge(n+i,ed,P[i],0);
        }
        addedge(st,n+1,k,0);
        for(int i=p;i<=n;i++)
            addedge(st,n+i,inf,q);
        for(int i=1;i<n;i++)
            addedge(i,i+1,inf,0);
        for(int i=1;i<n;i++)
            addedge(n+i,n+i+1,inf,0);
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
                if(i+T[j]<=n)
                    addedge(i,n+i+T[j],inf,S[j]);
        }
        int ans1=0,ans2=0;
        ans1=minCostMaxflow(st,ed,ans2);
        if(ans1==sum)printf("%d
    ",ans2);
        else printf("No solution
    ");
    }
    int main()
    {
        int t;
        scanf("%d",&t);
        while(t--)solve();
        return 0;
    }
  • 相关阅读:
    Android给ListView设置分割线Divider样式
    Android监听ScrollView滑动到顶端和底部
    .Net——使用.net内置处理程序处理自己定义节点Demo
    Java---25---集合框架共性方法
    网络基础——知识生活化会变得如此简单
    Jquery节点遍历
    Rapha&#235;l 中文帮助文档(API)
    Fitnesse使用系列二
    UVa 10188
    Powershell Mail module, 发送outbox 里的全部邮件(一个.csv文件代表一封邮件)
  • 原文地址:https://www.cnblogs.com/qscqesze/p/5270881.html
Copyright © 2011-2022 走看看