ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

JSOI2010盛夏的果实(最短路+二分答案)

2019-06-08 20:49:22  阅读:368  来源: 互联网

标签:JSOI2010 二分 果树 果实 短路 vis int spfa 篮子


本博客转自我校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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有