• 【BOI 2002】 双调路径


    双调路径

    题目传送门

    前言

    可能是我语文不太好,题目没读懂,感谢同桌帮助我理清题意


    题意

    对着图讲吧:

    如图,横轴表示花费的金钱,纵轴表示花费的时间,点表示一条路径

    1. ((5,5))和点((30,3))是优秀点

    2. ((10,10))、点((15,5))和点((23,8))是无用点

    来解释一下:

    1. ((5,5))明显比点((15,5))优秀,因为花费同样时间,花费金钱少的优秀

    2. ((10,10))和点((23,8))则肯定是无用点,因为它们花费的时间和金钱都多

    3. ((5,5))和点((30,3))都是优秀点,因为一个花费的金钱少,一个花费的时间少(相当于不同维度)

    推广为一般性问题:

    设我们当前的路径表示为((x,y)),下一条路径表示为((u,v))

    1. 如果 (u)(x) 小但 (v)(y) 大,那么两条路都暂为优秀

    2. 如果 (u)(x) 大但 (v)(y) 小,那么两条路都暂为优秀

    3. 如果 (u)(x) 小且 (v)(y) 小,那么((u,v))暂为优秀,而((x,y))一定为无用点


    分析

    题目要求求出从 (s)(e) 的最小路径条数

    理解了题意,那么应该很容易就能想出双限制的最短路做法吧(别在意名字...)

    什么意思?

    普通最短路就是距离限制,我们通过 (dis[x]) 表示到达点 (x) 的最小距离

    本题最短路则是限制距离(时间)和花费,那我们就加一维嘛!

    —— (dis[x][y]) 表示到达点 (x) 花费 (y) 块钱的最小距离(时间)

    最后枚举花费 (i) ,然后找到优秀点 (dis[e][i]),有多少优秀点答案就是多少

    怎么判断是否是优秀点?

    设一个变量 (ans) (=) (2005020600)(极大值就可以) ,如果当前的 (dis[e][i]) (<) (ans) ,则是优秀点( (ans) 表示的是时间)


    代码

    感觉上面讲的还是挺清楚了qwq,现在贴出代码:

    PS:没加树状数组优化什么的,跑得确实有点慢,(1s+)

    #include <bits/stdc++.h>
    using namespace std;
    queue<pair<int,int> > q;
    int n,m,s,E,p,r,c,t,tot,sum,ans=2005020600,maxn;
    int dis[101][30001],vis[101][3001],head[520010];
    
    struct node {
    	int to,ti,val,net;
    } e[520010];
    
    inline void add(int u,int v,int w,int tim) {
    	e[++tot].ti=tim;
    	e[tot].to=v;
    	e[tot].val=w;
    	e[tot].net=head[u];
    	head[u]=tot;
    }
    
    inline void spfa(int s) {   //其实就是板子 
    	for(register int i=1;i<=n;i++) {
    		for(register int j=0;j<=maxn;j++) {
    			dis[i][j]=2005020600;
    		}
    	}
    	dis[s][0]=0;    //到达点s花费0的最短时间为0 
    	vis[s][0]=1;
    	q.push(make_pair(s,0));   //为了不开两个queue,我选择开pair 
    	while(!q.empty()) {
    		int x=q.front().first;
    		int y=q.front().second;
    		q.pop();
    		vis[x][y]=0;
    		for(register int i=head[x];i;i=e[i].net) {
    			int v=e[i].to;
    			if(dis[v][y+e[i].val]>dis[x][y]+e[i].ti) {
    				dis[v][y+e[i].val]=dis[x][y]+e[i].ti;
    				if(!vis[v][y+e[i].val]) {
    					vis[v][y+e[i].val]=1;
    					q.push(make_pair(v,y+e[i].val));  //注意第二个存的是花费还不是dis[v][y+e[i].val]! 
    				}
    			}
    		}
    	}
    }
    
    int main() {
    	scanf("%d%d%d%d",&n,&m,&s,&E);
    	for(register int i=1;i<=m;i++) {
    		scanf("%d%d%d%d",&p,&r,&c,&t);
    		add(p,r,c,t);
    		add(r,p,c,t);
    		maxn+=c;   //maxn表示最多的花费上限 
    	}
    	spfa(s);
    	for(register int i=0;i<=maxn;i++) {  //枚举花费找答案 
    		if(dis[E][i]<ans) {
    			sum++;
    			ans=dis[E][i];
    		}
    	}
    	printf("%d",sum);
    	return 0;
    }
    

    最后,如果这篇题解有任何问题或不懂的地方,欢迎下方留言区评论,我会及时回复、改正,谢谢大家啊orz


  • 相关阅读:
    java日期格式转换工具类
    关于IOS给我的启发
    (转载)小米手机给我的启发和思考
    ElasticDownload
    ShopMall
    CycleViewPager
    MaterialImageView
    ZrcListView
    superCleanMaster
    QuickNewsLibs
  • 原文地址:https://www.cnblogs.com/Eleven-Qian-Shan/p/13372291.html
Copyright © 2020-2023  润新知