题目链接:

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

题意:

每天都有p[i]个飞行员进行阅兵,飞行员只工作一天。

m个休假公式,花费tt[i]元让飞行员在休假ss[i]天后回来上班。

可以花费Q元雇佣新的飞行员,但是直到P天后才能上班。

分析:

首先某一天雇佣的飞行员有三种可能:

1.原来就有的

  • 从s到第一天的结点连一条容量为k,费用为0的边。
  • 从第i天向第i+1天连一条容量为INF,费用为0的边。

2.新雇佣的:

  • 新雇佣的飞行员必须在P天后使用,所以在s和第P天的结点连一条容量为INF,费用为Q的边。

3.放假回来的:

(这里就不知道应该怎么处理了。)

其实仔细想,将每一天的结点都拆成两个,其中一个表示正常上班的情况,另一个用于表示飞行员休假回来上班的情况。也就是说:

  • 在第x[i]和第y[i+tt]结点之间连一条容量为INF,费用为ss的边,表示第i+tt天用的是第i天开始休假tt天后回来的飞行员的情况。

最后从s到x[i]建一条容量为p[i],费用为0的边,在y[i]到t同样建一条容量为p[i],费用为0的边,然后跑一下最小费用流判断是否满流就好啦~!

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
using namespace std;
const int maxm = 505;
const int INF = 0x3f3f3f3f;
int s, t, tot, all = 0;
int dist[maxm], prevv[maxm], preve[maxm], head[maxm];
bool in[maxm];
int maxflow;
struct Edge{ int from, to, next, cap, cost;}edge[maxm<<2];
void add_edge(int from, int to, int cap, int cost)
{
edge[tot].to = to;
edge[tot].from = from;
edge[tot].cap = cap;
edge[tot].cost = cost;
edge[tot].next = head[from];
head[from] = tot++;
edge[tot].to = from;
edge[tot].from = to;
edge[tot].cap = 0;
edge[tot].cost = -cost;
edge[tot].next = head[to];
head[to] = tot++;
}
bool spfa(int s, int t)
{
memset(dist, 0x3f, sizeof(dist));
memset(in, false, sizeof(in));
queue<int>q;
q.push(s);
in[s] = true;
dist[s]=0;
while(!q.empty()){
int u = q.front();q.pop();
in[u] = false;
for(int i = head[u]; i != -1; i = edge[i].next){
Edge e = edge[i];
if(e.cap >0 && dist[e.to] > dist[u] + e.cost){
dist[e.to] = dist[u] + e.cost;
prevv[e.to] = u, preve[e.to] = i;
if(!in[e.to]){
in[e.to] = true;
q.push(e.to);
}
}
}
}
if(dist[t] == INF) return false;
return true;
}
int MCMF(int s, int t)
{
int flow = 0, cost = 0;
while(spfa(s, t)){
int d = INF;
for(int i = t; i != s; i = prevv[i]){
d = min(d, edge[preve[i]].cap);
}
flow += d;
cost += dist[t] * d;
for(int i = t; i != s; i = prevv[i]){
edge[preve[i]].cap -= d;
edge[preve[i]^1].cap += d;
}
}
maxflow = flow;
return cost;
}
int main (void)
{
int T;scanf("%d",&T);
while(T--){
tot = 0;
memset(head, -1, sizeof(head));
int n, k; scanf("%d%d",&n, &k);
int s = 0, t = 2 * n + 1;
add_edge(s, n + 1, k, 0);
int p, ss, tt;
int all = 0;
for(int i = 1; i <= n; i++){
scanf("%d", &p);
all += p;
add_edge(s, i, p, 0);
add_edge(i + n, t, p, 0);
}
for(int i = 1; i < n; i++)
add_edge(i + n, i + n +1, INF, 0); int m, P, Q;
scanf("%d%d%d",&m, &P, &Q);
for(int i = P; i <= n; i++)
add_edge(s, i + n, INF, Q);
for(int i = 0; i < m; i++){
scanf("%d%d",&ss, &tt);
for(int j = 1; j <= n - tt; j++)
add_edge(j, n + j + tt, INF, ss);
} int res =MCMF(s, t);
if(maxflow != all) printf("No solution\n");
else printf("%d\n",res);
}
}

其实建图还是挺难想的。。。。

最新文章

  1. ReportViewer改变图表类型
  2. 并发-Java中的Copy-On-Write容器
  3. EditTextPreference点击后输入框显示隐藏内容,类似密码输入(转)
  4. 实现两个N*N矩阵的乘法,矩阵由一维数组表示
  5. Socket原理
  6. (大数据工程师学习路径)第四步 SQL基础课程----创建数据库并插入数据
  7. centos7 安装nodejs,git
  8. Spring MVC集成slf4j-logback
  9. D 洛谷 P3602 Koishi Loves Segments [贪心 树状数组+堆]
  10. php 时间戳最大值
  11. listview 样式 LVS_REPORT 与 LVS_EDITLABELS 编辑单元格时,当前行第一列内容不显示
  12. Confluence 6 修改日志文件的目标位置
  13. C++/JAVA/C#子类调用父类函数情况[留存]
  14. angular.js 教程 -- 实例讲解
  15. 基于axis1.4的webservice实例
  16. 【R】R语言常用函数
  17. ASP.NET 数据库缓存依赖
  18. Syslink Control in MFC 9.0(转)
  19. [UOJ213][UNR #1]争夺圣杯
  20. kali linux之steghide

热门文章

  1. Spring需要的几个关键配置文件(SSM框架整合)
  2. php debug/phpstorm调试
  3. Java语法基础-异常处理
  4. Microsoft SQL Server学习(二)
  5. AIX 10G HA RAC卸载
  6. C# 支持多线程
  7. PC端浏览器定位
  8. TYPE=MyISAM 与 ENGINE=MyISAM 的区别(摘要版)
  9. vs2019装了WDK后,编译其他vc工程,提示无法打开文件&quot;msvcprtd.lib&quot;
  10. freenas iscsi initiator 配置