Noip模拟 Day6.13 By LD T1

一、哲哲回家

【题目描述】:

哲哲放学了,准备坐公交车回家。因为急着回家看MSN战士,所以他想用最短的时间回家,但是因为学校离家里比较远,有时候他需要转几趟车才可以回家。等车是需要一段时间的,而且每辆公交车的速度不一样,哲哲晕掉了,不知道怎样才可以在最短的时间里回家,作为一名cjoier,你应该帮帮他。

现在一直哲哲所在的城市有N个公交站点(学校在一号站点,哲哲家在N号站点)和M条公交线路,每条公交线路是一个有序集合,公交线路i包含Pi个站点a[i,1],a[i,2]…a[i,Pi],表示i号公交车从a[i,1]出发,经过a[i,2],a[i,3]…a[i,Pi]又重新回到a[i,1]。

Ti,Ri分别表示等第i号公交车的时间和第i号公交车经过一站的时间(如果你当前处在第i条公交线路上,你可以花Ti的时间等到这辆车,然后这辆车会花Ri的时间经过一站,下车时间忽略不计)。

【输入】:

第一行两个数N,M,表示公交站点数和公交线路数。

以下M行,第i+1行每行前三个数为Ti,Ri,Pi,然后接着有Pi个数,第j+3个数表示a[i,j]。

【输出】:

仅一行,表示所需的最少时间。

【样例输入】:

3 3

3 3 3 1 2 3

10 1 2 1 3

1 1 2 3 2

【样例输出】:

8

【说明】:

哲哲从学校(1)出发坐1号公交车在2号站下,再从2号站转3号车到家。

20%的数据N,M≤10;

60%的数据N,M≤100;

100%的数据N,M≤500;Pi≤30。

出题人的解答:

可以将其转化成最短路模型。

这个地方转车怎么转移有点困难,有两种方法:

1.我们可以再把每一个点拆成M个点,我们用F[i,j]表示从1号点到i这个点并且坐在j路车上的最少费用,对于同一条线路的相邻两个点,我们连一条权值为Rj的边,对于不在同一条     线路的两个点,连一条Rj+Tk的边,最后的答案就是min{f[n,i]}(1≤i≤m);

2.我们定义f[i]为在点i处下车的最少费用,那么对于同一条路线上的点两两连边,费用为:经过的边数*Rj+Tk;可以发现Pi较小,使用后一种连边方式较优,点数是N,边数是M*P2。具体使用SPFA实现。

连边比较麻烦,我写Dijkstra+Heap

#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<vector>
#include<queue>
#include<cmath>
using namespace std;

typedef long long LL;

#define INF 1<<30
#define N 100010

struct edge
{
	int v,w,next;
}e[N];
int head[N];
int cnt;

struct data
{
	int to,len;
}p;

struct cmp
{
	bool operator()(const data a,const data b)
	{
		return a.len>b.len;
	}
};

int n,m,dian;
int t,r,pp;
int turn;

int vis[N],dist[N];

void link(int u,int v,int w)
{
	e[++cnt]=(edge){v,w,head[u]};
	head[u]=cnt;
}

void Dij(int s)
{
	priority_queue<data,vector<data>,cmp>q;
	for (int i=1;i<=dian;i++)
		dist[i]=INF;
	dist[s]=0;
	vis[s]=1;
	for (int i=head[s];i;i=e[i].next)
		if (dist[e[i].v]>dist[s]+e[i].w)
		{
			dist[e[i].v]=dist[s]+e[i].w;
			p.to=e[i].v;
			p.len=dist[p.to];
			q.push(p);
		}
	for (int i=1;i<=dian-1;i++)
	{
		if (q.empty())
			break;
		p=q.top();
		q.pop();
		while (vis[p.to] && !q.empty())
			p=q.top(),q.pop();
		int x=p.to;
		//	int len=p.len;
		vis[x]=1;
		for (int j=head[x];j;j=e[j].next)
			if (dist[e[j].v]>dist[x]+e[j].w)
			{
				dist[e[j].v]=dist[x]+e[j].w;
				p.to=e[j].v;
				p.len=dist[p.to];
				q.push(p);
			}
	}
}

int main()
{
	freopen("home.in","r",stdin);freopen("home.out","w",stdout);
	scanf("%d%d",&n,&m);
	dian=n+1;
	for (int i=1;i<=m;i++)
	{
		scanf("%d%d%d",&t,&r,&pp);
		for (int j=1;j<pp;j++)
		{
			scanf("%d",&turn);
			link(turn,dian,t);
			link(dian,turn,0);
			link(dian,dian+1,r);
			dian++;
		}
		link(dian,dian+1-pp,r);
		scanf("%d",&turn);
		link(turn,dian,t);
		link(dian,turn,0);
		dian++;
	}
	Dij(1);
	printf("%d\n",dist[n]);
	return 0;
}

  

机房另外一个神犇写了spfa

#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <ctime>
#include <vector>
#include <queue>
#include <map>
#include <set>
#ifdef WIN32
#define OT "%I64d"
#else
#define OT "%lld"
#endif
using namespace std;
typedef long long LL;
const int MAXN = 520;
const int inf = (1<<30);
int n,m;
int dis[MAXN][MAXN];
int next[MAXN][MAXN];
int T[MAXN],R[MAXN],p[MAXN][MAXN];
bool pd[MAXN][MAXN];

struct node{
    int x,y;
};

queue<node>Q;
int ans;

inline int getint()
{
	int w=0,q=0;
	char c=getchar();
	while((c<‘0‘ || c>‘9‘) && c!=‘-‘) c=getchar();
	if (c==‘-‘)  q=1, c=getchar();
	while (c>=‘0‘ && c<=‘9‘) w=w*10+c-‘0‘, c=getchar();
	return q ? -w : w;
}

inline void spfa(){
    for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			dis[i][j]=inf;

    while(!Q.empty()) Q.pop();

    node lin;
    for(int i=1;i<=n;i++)
		if(next[i][1]!=0){
			lin.x=i; lin.y=1;
			Q.push(lin);
			dis[i][1]=T[i];
			pd[i][1]=1;
		}

    while(!Q.empty()) {
		int x=Q.front().x; int y=Q.front().y; Q.pop();
		pd[x][y]=0;
        for(int i=1;i<=n;i++) {
			if(i!=x) {
				if(next[i][y]==0) continue;
				if(dis[i][y]>dis[x][y]+T[i]) {
					dis[i][y]=dis[x][y]+T[i];
					if(!pd[i][y]) {
						pd[i][y]=1;
						lin.x=i; lin.y=y;
						Q.push(lin);
					}
				}
			} else{
				if(dis[x][next[x][y]]>dis[x][y]+R[i]) {
					dis[x][next[x][y]]=dis[x][y]+R[i];
					if(!pd[x][next[x][y]]) {
						pd[x][next[x][y]]=1;
						lin.x=x; lin.y=next[x][y];
						Q.push(lin);
					}
				}
			}
		}
    }

    ans=inf;
    for(int i=1;i<=n;i++) {
		if(dis[i][n]<ans) ans=dis[i][n];
    }
}

inline void solve(){
    n=getint(); m=getint();
    for(int i=1;i<=m;i++) {
		T[i]=getint(); R[i]=getint(); p[i][0]=getint();
		for(int j=1;j<=p[i][0];j++) {
			p[i][j]=getint(); if(j!=1) next[i][p[i][j-1]]=p[i][j];
		}
		if(p[i][0]>0) next[i][p[i][p[i][0]]]=p[i][1];
    }

    spfa();

    printf("%d",ans);
}

int main()
{
	freopen("home.in","r",stdin);
	freopen("home.out","w",stdout);
	solve();
	fclose(stdin);
	fclose(stdout);
	return 0;
}

  

时间: 2024-10-10 13:08:33

Noip模拟 Day6.13 By LD T1的相关文章

NOIP模拟17.8.17

NOIP模拟17.8.17 A 小 G 的字符串文件名 输入文件 输出文件 时间限制 空间限制str.pas/c/cpp str.in str.out 1s 128MB[题目描述]有一天,小 L 给小 G 出了这样一道题:生成一个长度为 n 的.全由小写英文字母构成的字符串,只能使用 k 种字母.要求满足:• 字符串中相邻的两个字母不能相同.• 必须出现恰好 k 种不同的字母.这样的合法字符串可能有很多,小 L 让小 G 输出字典序最小的那个.小 G 太笨啦,不会做这道题,希望你帮帮他.[输入格

NOIP模拟 17.8.18

NOIP模拟17.8.18 A.小菜一碟的背包[题目描述]Blice和阿强巴是好朋友但萌萌哒Blice不擅长数学,所以阿强巴给了她一些奶牛做练习阿强巴有 n头奶牛,每头奶牛每天可以产一定量的奶,同时也需要一定量的草作为饲料对于第 i头奶牛来说,它每天可以产 vi升的奶,同时需要 wi千克的草作为饲料现在来自蚯蚓国的九条可怜想借一些奶牛,使借走的这些奶牛每天的总产奶量最大,但九条可怜很穷,每天最多只能提供W千克的草作为饲料,而且她还需要对付跳蚤国的神刀手,所以她把这个问题交给了阿强巴,不不不……阿

NOIP模拟17.9.21

NOIP模拟17.9.21 1 任务安排manage.in/.out/.cpp1.1 问题描述你有N 个工作,同一时刻只能做一个任务, 其中每个工作有其所需时间, 及完成的Deadline(截止时间), 问要完成所有工作, 最迟要从什么时候开始.你最早可以从时间0 开始工作.1.2 输入格式第一行一个整数N,表示任务数量接下来n 行,每行两个整数,Ti; Si,分别表示该任务的持续时间和截止时间.1.3 输出格式输出一个整数,表示最晚的开始时间,如果不能完成,输出-1.1.4 样例输入43 58

NOIP模拟17.9.22

NOIP模拟17.9.22 前进![问题描述]数轴的原点上有一只青蛙.青蛙要跳到数轴上≥ ??的位置去,但很不幸数轴上有??个区间是禁区,不能进入.青蛙会选择一个长度??,从原点开始每次向右跳长度为??的一段.一路上青蛙会停的位置是0, ??, 2??,…直到跳到了≥ ??的位置,任意一个位置都不能在禁区中.请求出??的最小值,注意??可以是实数.[输入格式]输入文件为susume.in.输入文件的第一行包含两个整数??和??,含义如问题描述中所述.接下来??行,每行描述一个禁区.每行有两个整数

noip模拟测试11

T1:string 第一眼秒出思路,这不就是排序那道题的加强版吗? 然而歪?解复杂度虽然是对的,但常数过大,竟被卡到70 歪?解:(实际上std写的就是这个,但据说std被卡掉了 OAO) 因为字符集很小,所以我们可以把区间排序改为区间查询和覆盖 即:先查询区间内所有字符的个数,再从左端点开始按照大小关系依次将长度为字符个数的区间修改为该字符. 期望复杂度O ( 26*mlogn ),实际复杂度O ( 26*mlogn*(巨大的常数) ) 所以需要一(feng)定(kuang)的卡常 正?解:

noip模拟测试21

T1:折纸 这道写崩我也是没话说…… 模拟就完了,记录每次的折叠点,每次将之前的都扫一遍就完了 1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<cmath> 5 #include<algorithm> 6 #include<cstdlib> 7 #define ll long long 8 using namespace std; 9 con

NOIP模拟赛

#1[Nescafé 31]杯NOIP模拟赛 t1 题意:n*m的棋盘上从(1,1)走到(n,m),只能向下或向右,一些格子有老鼠,每个老鼠互不相同,当处于与老鼠有重边的格子时,视为看见了这只老鼠,求到终点看到最少的不同老鼠数. 分析:DP 由于求得是看到的不同的老鼠数目,不能直接用过河卒做,因为同一个位置的老鼠可能会统计多次,我们还需要增加一维即方向. f[i,j,0]表示到从上面一个格子走到(i,j)时最少老鼠数,f[i,j,1]表示左边. f[i,j,0]:=min(f[i-1,j,0]+

NOIP模拟 6.28

NOIP模拟赛6.28 Problem 1 高级打字机(type.cpp/c/pas) [题目描述] 早苗入手了最新的高级打字机.最新款自然有着与以往不同的功能,那就是它具备撤销功能,厉害吧. 请为这种高级打字机设计一个程序,支持如下3种操作: 1.T x:在文章末尾打下一个小写字母x.(type操作) 2.U x:撤销最后的x次修改操作.(Undo操作) (注意Query操作并不算修改操作) 3.Q x:询问当前文章中第x个字母并输出.(Query操作) 文章一开始可以视为空串. [输入格式]

NOIP模拟赛 6.29

2017-6-29 NOIP模拟赛 Problem 1 机器人(robot.cpp/c/pas) [题目描述] 早苗入手了最新的Gundam模型.最新款自然有着与以往不同的功能,那就是它能够自动行走,厉害吧. 早苗的新模型可以按照输入的命令进行移动,命令包括‘E’.‘S’.‘W’.‘N’四种,分别对应东南西北.执行某个命令时,它会向对应方向移动一个单位.作为新型机器人,它可以执行命令串.对于输入的命令串,每一秒它会按命令行动一次.执行完命令串的最后一个命令后,会自动从头开始循环.在0时刻时机器人