zz's Mysterious Present HDU - 2145

傻逼题目,毁我青春

题意

若干人在不同地点,去zz家参加party,最先到的人可获得礼物。每个人都会走从自己家到zz家的最短路,每个人的速度都不同。同时到的话,离zz家远的获得礼物;离zz家一样远的话,序号大的人获得礼物。问最终谁获得礼物。

 

输入

地址数n,人数m,边数k

k行:a, b, c 有向边的端点和权重

1个数:目标地址zz家

m个数:m个人所在地址

m个数:m个人的速度

 

输出

得到礼物的人的序号

 

思路:最短路水题(写了三个小时WA了13发的我,看到网上都说这道题是水题,很生气,我也要说它是水题,哼)

 

AC代码1(SPFA+邻接矩阵):

#include<bits/stdc++.h>
using namespace std;
const int INF=0x3f3f3f3f;
const int N=305;
int g[N][N];
int p[N],v[N];
int n,m,k;
bool st[N];
int dist[N];

void spfa(int s){
	memset(dist,0x3f,sizeof dist);
	dist[s]=0;
	
	queue<int>q;
	q.push(s);
	st[s]=true;
	
	while(!q.empty()){
		int t=q.front();
		q.pop();
		st[t]=false;
		
		for(int i=1;i<=n;++i){
			if(dist[i]>dist[t]+g[t][i]){
				dist[i]=dist[t]+g[t][i];
				if(!st[i]){
					q.push(i);
					st[i]=true;
				}
			}
		}
	}
}

int main(){
	
	while(scanf("%d%d%d",&n,&m,&k)!=EOF){ //For each case
		memset(g,0x3f,sizeof g);
		memset(st,0,sizeof st);
		for(int i=0;i<k;++i){
			int a,b,c;
			scanf("%d%d%d",&a,&b,&c);
			g[b][a]=min(g[b][a],c);//反向边
		}
		int s;
		scanf("%d",&s);
		for(int i=1;i<=m;++i) scanf("%d",&p[i]);
		for(int i=1;i<=m;++i) scanf("%d",&v[i]);
		
		spfa(s);
		double t,mint=INF;
		int ans=0;
		for(int i=1;i<=m;++i){
			t=1.0*dist[p[i]]/(1.0*v[i]);
			if(t<mint){
				mint=t;
				ans=i;
			}else if(t==mint){//浮点数比大小 写成<eps更严谨
				if(dist[p[i]]>=dist[p[ans]]) ans=i; // >= 序号是按从小到大枚举的,距目的地距离相同的情况下,ans=i,即为了题目中的条件“序号大的人获得礼物”
			}
		}
		if(dist[p[ans]]==INF) puts("No one");//非常严谨
		else printf("%d\n",ans);

	}
}

 

AC代码2(SPFA+邻接表)快很多,内存又少

#include<bits/stdc++.h>
using namespace std;
const int INF=0x3f3f3f3f;
const int N=305,M=5005;
int h[N],e[M],ne[M],w[M],idx;
int p[N],v[N];
int n,m,k;
bool st[N];
int dist[N];
void add(int a,int b,int c){
	e[idx]=b,ne[idx]=h[a],w[idx]=c,h[a]=idx++;
}

void spfa(int s){
	memset(dist,0x3f,sizeof dist);
	dist[s]=0;
	
	queue<int>q;
	q.push(s);
	st[s]=true;
	
	while(!q.empty()){
		
		int t=q.front();
		q.pop();
		st[t]=false;
		
		for(int i=h[t];~i;i=ne[i]){
			int j=e[i];
			if(dist[j]>dist[t]+w[i]){
				dist[j]=dist[t]+w[i];
				if(!st[j]){
					q.push(j);
					st[j]=true;
				}
			}
		}
		
	}
}

int main(){
	
	while(scanf("%d%d%d",&n,&m,&k)!=EOF){
		memset(h,-1,sizeof h);
		memset(st,0,sizeof st);
		idx=0;
		for(int i=0;i<k;++i){
			int a,b,c;
			scanf("%d%d%d",&a,&b,&c);
			add(b,a,c);
		}
		int s;
		scanf("%d",&s);
		for(int i=1;i<=m;++i) scanf("%d",&p[i]);
		for(int i=1;i<=m;++i) scanf("%d",&v[i]);
		
		spfa(s);
		double t,mint=INF;
		int ans=0;
		for(int i=1;i<=m;++i){
			t=1.0*dist[p[i]]/(1.0*v[i]);
			if(t<mint){
				mint=t;
				ans=i;
			}else if(t==mint){
				if(dist[p[i]]>=dist[p[ans]]) ans=i; 
			}
		}
		if(dist[p[ans]]==INF) puts("No one");
		else printf("%d\n",ans);

	}
}

 

注意

 

1. 最短路部分:

每个点目标点的最短路——反向建图!用Dijkstra或SPFA跑从源点其余每个点的最短路!

其他没什么好说的了,默写模板

ps: Floyd会T(不知道几组case)

 

2. 排序部分:

跑完最短路算法,开始“排序”。

我一开始对于No one的情况,单独写了一个循环去判断:遍历m个人的dist,如果全是INF,就输出No one,其实没必要。

然后改成了现在的写法

我原先以为这种写法不行

“因为如果某地到不了,但速度很大,t就有可能把别的能到的、但速度很小的-->因而t较大的答案更新掉

所以即便 dist[p[ans]]==INF,ans之前可能存过dist[p[ans]]<INF的合法答案,但是被冲掉了” (WA久了怀疑一切WA点)

但看下数据范围:

0<speed[i]<=100,0<n<=300, 0<m<=n, 0<k<5000,0<a,b<=n, 0<c<=100

一个能到达的地点,时间最长是5000*100/1==500000

一个到不了的地点(INF),时间最短是0x3f3f3f3f/100==1061109567/100==10611095.67,不可能更新别人

所以经过周密的数据范围的分析,这样写是可以的!

 

3. puts("No one\n") —— presentation error   

    puts相当于java里的println?自带回车啊。

 

4.最坑的点,题目中Input没提多组输入,但是输出部分:

Output

For each case, output the one who get the present in one line. If no one can get the present, output "No one". 

 有个“For each case”!太贱了。

拜拜了您!

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值