hdu 5644 King's Pilots(bestcoder #75 1005)

本文探讨了在阅兵式期间飞机表演的飞行员调度问题,包括每天所需飞行员数量、休假制度、新飞行员招募时间及成本,旨在通过建图思想求解最小化总费用的最优方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Problem 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;

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

中文:
问题描述
国王阅兵式会持续 nn 天,每天都有一场飞机表演,第 ii 天的飞行表演需要 P_iP
​i
​​ 个飞行员。由于每个飞行员都不愿意无偿的连续工作(哪怕连续工作 2 天 , 因为他们实在太困了),这个国家出台了 mm 个休假办法,当某个飞行员当天工作后,如果支付他 S_jS
​j
​​ 的酬劳,他会在上次工作 T_jT
​j
​​ 天后重新回来工作 (1\le j\le m)(1≤j≤m)。(多么好的制度)

如果飞行员在第 rr 天工作且此时 T_j = 1T
​j
​​ =1,那么他会就在 r+1r+1 天继续工作。

一开始有 kk 名飞行员,但当然还可以招募新的飞行员,但是,招募需要 PP 天的时间,并且招募来的每个飞行员需要支付 QQ 作为酬劳。(也就意味着到第 PP 天你才可能用到新招募来的飞行员)

现在国王把安排飞行表演的任务交给了你,你需要合理的安排这次飞行表演使得每天的飞行员都是充足的,并且让总费用最低。最后请输出总费用。
输入描述
第一行一个整数表示测试组数:T(T\le 5)T(T≤5)

对于每组数据,第一行两个整数 n (n\le 200)n(n≤200),kk 表示阅兵式的天数和一开始的飞行员数量。

第二行 nn 个数,用空格分隔,表示每一天所需要的飞行员的数目。

第三行 3 个整数 m(m \le 5),P, Qm(m≤5),P,Q, 具体意义参见题面。

接下来的 mm 行每行 2 个整数,即 S_i, T_iS
​i
​​ ,T
​i
​​ 。

输入的所有数据均在区间 [0 , 200][0,200] 内
输出描述
对每组数据输出一行表示答案 , 即最小费用。

如果无解输出 No solution

注: 整个过程不会超出32位带符号整数
输入样例
1
5 10
1 3 5 10 6
1 3 5
2 2
输出样例
48

官方题解,说的很清楚了,
最小费用最大流

代码:
(这次代码写的很清晰,应该很好懂~当然主要是要学会建图的思想)



#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <ctime>
#include <algorithm>
#include <iostream>
#include <sstream>
#include <string>
#include <queue>
#define oo 0x13131313
using namespace std;
const int MAXN=405;
const int MAXM=400010;
const int INF=0x3f3f3f3f;
struct Edge
{
    int to,next,cap,flow,cost;
    void get(int a,int b,int c,int d)
    {
        to=a,cap=b,cost=c;next=d;flow=0;
    }
}edge[MAXM];
int head[MAXN],tol;
int pre[MAXN],dis[MAXN];
bool vis[MAXN];
int N;
void init(int n)
{
    N=n;
    tol=0;
    memset(head,-1,sizeof(head));
}
void addedge(int u,int v,int cap,int cost)
{
    edge[tol].get(v,cap,cost,head[u]);head[u]=tol++;
    edge[tol].get(u,0,-cost,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;
}
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;
}
int n,k;
int p[402];
int s[402],t[402];
int m,P,q;
void input()
{
    int sum=0;
   int ans=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);
   int st=0,sd=n*2+1;
   for(int i=1;i<=m;i++)
   {
       scanf("%d%d",&s[i],&t[i]);
       for(int j=1;j<=n;j++)
       {
           if(j+n+t[i]<=n*2)
            addedge(j,j+n+t[i],INF,s[i]);
       }
   }

   for(int i=1;i<=n;i++)
   {
       addedge(st,i,p[i],0);
   }
   for(int i=n+1;i<=2*n;i++)
   {
       addedge(i,sd,p[i-n],0);
   }
   addedge(st,n+1,k,0);
   for(int i=P+n;i<=2*n;i++)
   {
       addedge(st,i,INF,q);
   }
   for(int i=1;i<n;i++)
   {
       addedge(i,i+1,INF,0);
       addedge(i+n,i+n+1,INF,0);
   }

   if(minCostMaxflow(st,sd,ans)==sum)
   cout<<ans<<endl;
   else
    cout<<"No solution"<<endl;
}

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        init(MAXN);
        input();
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值