JSOI2010盛夏的果实(最短路+二分答案)
作者:互联网
本博客转自我校LJY巨佬的博客并经过本人许可
盛夏的果实(最短路+二分答案)
我也不知道这道题是哪来的,可能是我们老师原创的,其实是JSOI2010的水题,锻炼下思维
题干:
描述
丛林中共有n棵果树,每一棵果树上都有数量不等的果实。果树之间有单向边连接,而且从任何一棵果树开始不可能通过若干单向边走回自身。你提着一个篮子从编号为1的果树出发,选择一条路径走到编号为n的果树。每当你走到一棵果树的时候,你都会将这棵果树的所有果实采摘下来,放入篮子中,假设这个过程是不花费任何时间的。而当你在路上行走的时候,每走1分钟,你都会从篮子中拿出一个果实吃掉(如果篮子里还有果实的话)。
你的任务是求出你所携带的篮子至少要能够承担多少个果实的重量,才能够顺利地选择一条路径完成旅途,并且在途中不扔掉任何果实。(当到达第n棵果树时,还是要将这棵果树的全部果实放入篮子中)。
输入
输入文件第一行为两个整数 ,n,m分别表示果树的个数与单向边的条数。所有的果树从1到n编号。
接下来一行, n个用空格隔开的整数,分别表示编号1~ 的果树上果实的个数。
接下来m行,每行三个用空格隔开的整数 ,表示从 到 有一条单向边相连,这条边通过所需的时间为 (分钟)。
输出:
输出文件有且仅有一行,一个整数,表示篮子最少需要承担多少个果实的重量。
样例输入
4 4
5 7 6 4
1 2 3
1 3 3
2 4 100
3 4 1
样例输出
9
提示:
1.1<=N<=1000 1<=M<=5000
2, 两颗不同树之间可能有多条边直接相连,但是没有一条边连接两颗相同的树。
3,一定存在至少一条从树1到达树n的路径。
4. 每棵树上果实的数量,通过一条边所需的时间都是1~10000之间的整数。
6,5对于30%的数据,N<=10,M<=2- 。
6. 对于60%的数据, N<=100 M<=300
怎么做呢:
-
问题:你发现到达果篮上限的值在途中的某个位置,不好判断。
所以:二分答案,问题转化为验证果篮大小a的时候能否实现 -
验证的过程可以用最短路实现,设f[i]表示在i树摘完果子后可以省下的最少果子数,若超过a则抛弃
-
更新:如果u到v有一条连边则:
f[v]=max(f[v],max(f[u]-(u到v的边长))+v的果子数) -
像最短路一样松弛即可,理论上spfa、福特、dijkstra(可以不用堆优化)都行
特别注意:
- 1.spfa内要与0取max(代码里有详细解释)
- 2.要特判出发点(代码里有详细解释)
- 3.注意二分下界一定不是所有点权的最大值而是起点、终点最大值,因为有一些点权过大的点可以不走(保证正确性)
spfa+二分的ac代码:
#include<bits/stdc++.h>
using namespace std;
const int N=1005,M=5005;
int n,m,tot;
struct edge{
int nxt,from,to,val;
}e[M];
int fir[N],id[N],f[N],vis[N];
//id表示点权,val表示边权
queue<int> q;
void add(int u,int v,int w){//建边
e[++tot]={fir[u],u,v,w};
fir[u]=tot;
}
bool spfa(int x){
memset(f,0x3f,sizeof(f));
memset(vis,0,sizeof(vis));
q.push(1);vis[1]=1;f[1]=id[1];
while(!q.empty()){
int u=q.front();q.pop();
vis[u]=0;
for(int i=fir[u];i;i=e[i].nxt){
int v=e[i].to,now=max(0,f[u]-e[i].val)+id[v];
//一定要与0作比较:吃完了就不能再吃了
//一开始打掉了这一句,wa了半个小时,555
if(now>x||now>=f[v])continue;
f[v]=now;
if(!vis[v]){
q.push(v);
vis[v]=1;
}
}
}
return f[n]<=x;
}
int main(){
scanf("%d%d",&n,&m);
int r=0;
for(int i=1;i<=n;i++)scanf("%d",&id[i]);
for(int i=1;i<=m;i++){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
r+=w;
add(u,v,w);
}
int l=max(id[1],id[n]);//此处r是所有点权的总和,保证正确性
//注意代码细节:这里l不会低于id[1],保证在出发时是合法的
//否则有可能在1号节点出发就非法,而经过一条边后有合法了,这不行
//如果l取1则需要在spfa内特判
//其实不特判在woj上还是能ac,但换特殊数据就不一定了
//至于id[n],是节省时间用的,可以删去;
while(l<r){
int mid=l+r>>1;
if(spfa(mid))r=mid;
else l=mid+1;
}
printf("%d",l);
return 0;
}
完结散花qwq
作者:李贰���
来源:CSDN
原文:https://blog.csdn.net/avenLJY/article/details/90747959
版权声明:本文为博主原创文章,转载请附上博文链接!
标签:JSOI2010,二分,果树,果实,短路,vis,int,spfa,篮子 来源: https://blog.csdn.net/qq_42754826/article/details/91347502