一、哲哲回家
【题目描述】:
哲哲放学了,准备坐公交车回家。因为急着回家看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; }