题目传送门(内部题149)


输入格式

  每个测试点第一行为四个正整数$n,b,s,m$,含义如题目所述。
  接下来$m$行,每行三个非负整数$u,v,l$,表示从点$u$到点$v$有一条权值为$l$的有向边,数据保证图是强连通的,也就是任意两个点之间都可以互相走到。


输出格式

  对每组数据输出一行一个非负整数表示答案。


样例

样例输入1:

5 4 2 10
5 2 1
2 5 1
3 5 5
4 5 0
1 5 1
2 3 1
3 2 5
2 4 5
2 1 1
3 4 2

样例输出1:

13

样例输入2:

5 4 2 10
5 2 1
2 5 1
3 5 5
4 5 10
1 5 1
2 3 1
3 2 5
2 4 5
2 1 1
3 4 2

样例输出2:

24


数据范围与提示

  每个测试点$5$分,各个测试点数据范围如下:

  除此之外,数据中可能会均匀出现一些$s$值比较小的点。
  对于所有的测试点,均有$m\leqslant 50,000,1\leqslant s\leqslant b<n,0\leqslant l\leqslant 10,000$,给定的有向图合法且强连通。


题解

先求出每个点到总部的正反最短路,建反向边即可。

化一下式子即可发现每一个点的代价为它的正反最短路长度和乘上它所在子项目有几个分部$-1$。

利用贪心的思想,小的放在一起,大的放在一起一定更优,于是可以排个序。

接着考虑$DP$,设$dp[i][j]$表示选到$i$,分了$j$组的最小代价,但是发现时间复杂度是$\Theta(n^3)$的,接着考虑优化。

在最优解中$dis$从小到大依次划分得到的段的长度一定是单调不增的,所以只有$[i-\frac{i}{j},i)$才能更新$dp[i][j]$。

那么现在算法的时间复杂度就是:$\Theta(n^2(\frac{1}{1}+\frac{1}{2}+\frac{1}{3}+...+\frac{1}{n}))=\Theta(n^2\log n)$。

由于时限为$3s$所以跑过去绰绰有余。

时间复杂度:$\Theta(n^2\log n)$。

期望得分:$100$分。

实际得分:$100$分。


代码时刻

#include<bits/stdc++.h>
using namespace std;
struct rec{int nxt,to,w;}e[100001];
int head[2][5001],cnt;
int n,b,s,m;
int dis[2][5001];
bool vis[5001];
long long sum[5001],dp[5001][5001];
priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>>q;
void add(bool id,int x,int y,int w)
{
e[++cnt].nxt=head[id][x];
e[cnt].to=y;
e[cnt].w=w;
head[id][x]=cnt;
}
void Dij0()
{
q.push(make_pair(0,b+1));
dis[0][b+1]=0;
while(q.size())
{
int x=q.top().second;q.pop();
if(vis[x])continue;vis[x]=1;
for(int i=head[0][x];i;i=e[i].nxt)
if(dis[0][e[i].to]>dis[0][x]+e[i].w)
{
dis[0][e[i].to]=dis[0][x]+e[i].w;
q.push(make_pair(dis[0][e[i].to],e[i].to));
}
}
}
void Dij1()
{
memset(vis,0,sizeof(vis));
q.push(make_pair(0,b+1));
dis[1][b+1]=0;
while(q.size())
{
int x=q.top().second;q.pop();
if(vis[x])continue;vis[x]=1;
for(int i=head[1][x];i;i=e[i].nxt)
if(dis[1][e[i].to]>dis[1][x]+e[i].w)
{
dis[1][e[i].to]=dis[1][x]+e[i].w;
q.push(make_pair(dis[1][e[i].to],e[i].to));
}
}
}
int main()
{
scanf("%d%d%d%d",&n,&b,&s,&m);
for(int i=1;i<=m;i++)
{
int a,b,l;
scanf("%d%d%d",&a,&b,&l);
add(0,a,b,l);add(1,b,a,l);
}
memset(dis,0x3f,sizeof(dis));
Dij0();Dij1();
for(int i=1;i<=b;i++)
sum[i]=dis[0][i]+dis[1][i];
sort(sum+1,sum+b+1);
for(int i=1;i<=b;i++)sum[i]+=sum[i-1];
memset(dp,0x3f,sizeof(dp));
dp[0][0]=0;
for(int i=1;i<=b;i++)
for(int j=1;j<=s;j++)
for(int k=i-i/j;k<i;k++)
{
if((sum[i]-sum[k])*(i-k-1)>=dp[i][j])break;
dp[i][j]=min(dp[i][j],dp[k][j-1]+(sum[i]-sum[k])*(i-k-1));
}
printf("%lld",dp[b][s]);
return 0;
}

rp++

[CSP-S模拟测试]:任务分配(最短路+贪心+DP)的更多相关文章

  1. [CSP-S模拟测试]:二叉搜索树(DP+贪心)

    题目传送门(内部题99) 输入格式 第一行一个整数$n$,第二行$n$个整数$x_1\sim x_n$. 输出格式 一行一个整数表示答案. 样例 样例输入: 58 2 1 4 3 样例输出: 数据范围 ...

  2. [CSP-S模拟测试]:C(三分+贪心)

    题目传送门(内部题46) 输入格式 第一行$3$个整数$n,m,t$.第二行$n$个整数,表示$P_i$.接下来$m$行每行两个整数,表示$L_i,R_i$. 输出格式 一行一个整数表示答案. 样例 ...

  3. [CSP-S模拟测试]:括号密码(贪心)

    题目描述 在“无限神机”的核心上,有一个奇怪的括号密码,密码初始已经有一个括号序列,有$n$个限制条件,每个限制条件描述为$l_i$和$r_i$,表示区间$[l_i,r_i]$的括号序列必须合法.调整 ...

  4. [CSP-S模拟测试]:trade(反悔贪心)

    题目传送门(内部题62) 输入格式 第一行有一个整数$n$.第二行有$N$个整数:$a_1\ a_2\ a_3\cdot\cdot\cdot a_n$. 输出格式 一行一个整数表示最大收益. 样例 样 ...

  5. [CSP-S模拟测试]:Graph(图论+贪心)

    题目描述 给定一张$n$个点$m$条边的无向图,每条边连接两个顶点,保证无重边自环,不保证连通你想在这张图上进行若干次旅游,每次旅游可以任选一个点$x$作为起点,再走到一个与 $x$直接有边相连的点$ ...

  6. [CSP-S模拟测试]:虎(DFS+贪心)

    题目传送门(内部题15) 输入格式 第一行一个整数$n$,代表点数接下来$n-1$行,每行三个数$x,y,z$,代表点$i$与$x$之间有一条边,若$y$为$0$代表初始为白色,否则为黑色,若$z$为 ...

  7. [CSP-S模拟测试]:Emotional Flutter(贪心)

    题目传送门(内部题51) 输入格式 第一行一个整数$t$表示数据组数.每组数据的第一行有三个整数$s,k,n$.第二行有$n$个整数$A_1,A_2,...,A_n$,依次表示黑白条的长度. 输出格式 ...

  8. 联赛模拟测试25 C. Repulsed 贪心+树形DP

    题目描述 分析 考虑自底向上贪心 \(f[x][k]\) 表示 \(x\) 下面距离为 \(k\) 的需要灭火器的房间数,\(g[x][k]\) 表示 \(x\) 下面距离为 \(k\) 的多余灭火器 ...

  9. [CSP-S模拟测试]:字符交换(贪心+模拟)

    题目传送门(内部题136) 输入格式 输入文件第一行为两个正整数$n,k$,第二行为一个长度为$n$的小写字母字符串$s$. 输出格式 输出一个整数,为对字符串$s$进行至多$k$次交换相邻字符的操作 ...

随机推荐

  1. QT 获取字体大小

    QFont font(androidFont); QFontInfo fInfo(font); qDebug()<<"FFFFFFFFFFFFFFFFFFFFFFFPPPSIZE ...

  2. O059、Backup Volume 操作

    参考https://www.cnblogs.com/CloudMan6/p/5662236.html   BackUp是将Volume备份到别的地方(备份设备),将来可以通过restore操作恢复. ...

  3. Centos7:MyCat安装,配置及使用

    解压缩 使用,默认端口8066 ./mycat start //启动 ./mycat stop //停止 ./mycat restart //重启

  4. Centos6.8 rabbitmq搭建且修改默认端口

    一.安装依赖环境 yum install build-essential openssl openssl-devel unixODBC unixODBC-devel make gcc gcc-c++ ...

  5. im_master_search_specification

    中文 http://accel-archives.intra-mart.jp/2014-winter/document/iap/public_zh_CN/im_master/im_master_sea ...

  6. Centos7下查看端口占用

    netstat -nap #会列出所有正在使用的端口及关联的进程/应用 netstat -lnp|grep 5000 这条语句的作用是查询占用5000端口的应用和进程,把5000端口替换成你要过滤的端 ...

  7. 《python解释器源码剖析》第9章--python虚拟机框架

    9.0 序 下面我们就来剖析python运行字节码的原理,我们知道python虚拟机是python的核心,在源代码被编译成字节码序列之后,就将有python的虚拟机接手整个工作.python虚拟机会从 ...

  8. linux基础—课堂随笔08_进程(转)

    进程优先级 命令 pstree -p 显示各个子线程 ps 进程状态(process state) UNIX风格:ps -ef BSD风格:ps aux 还有用到o参数,选项显示定制的信息: pid. ...

  9. cubase 的 CC控制器使用

  10. 分析bug是前端还是后端的

    如何分析一个bug是前端还是后端的? 平常提bug的时候,前端开发和后端开发总是扯皮,不承认是对方的bug 这种情况很容易判断,先抓包看请求报文,对着接口文档,看请求报文有没问题,有问题就是前端发的数 ...