【csuoj1014】 西湖三人行
http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1014 (题目链接)
题意
从无向图图上一点到达另一点,可以步行,搭公交或者是打的,不同的交通方式花的钱不同,当然消耗的时间也不同。求从起点S到终点T在花费的总钱数少于L的情况下的最短时间。
Solution
应YZC的邀请做了这道题,就是一个分层图最短路,转移有点恶心。
细节
注意初始化,以及公交车两两之间走的不是最短路,而是两点之间的直接相连的边。
代码
// csuoj1014 #include<algorithm> #include<iostream> #include<cstdlib> #include<cstring> #include<cstdio> #include<vector> #include<cmath> #include<queue> #define LL long long #define inf 1000000000 #define Pi acos(-1.0) #define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout); using namespace std; const int maxn=200,maxm=1010,maxw=3010; struct edge {int to,next,w;}e[maxm<<1]; struct data {int num,w;}; int head[maxn],vis[maxn][maxw],t[maxn][maxn],n,m,S,T,B,L,cnt; int dis[maxn][maxw],f[maxn][maxn],d[maxn][maxn]; vector<int> v[maxn]; queue<data> q; void link(int u,int v,int w) { e[++cnt].to=v;e[cnt].next=head[u];head[u]=cnt;e[cnt].w=w; e[++cnt].to=u;e[cnt].next=head[v];head[v]=cnt;e[cnt].w=w; } void Init() { for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) f[i][j]=d[i][j]=inf; for (int i=1;i<=n;i++) f[i][i]=head[i]=0; for (int i=1;i<=n;i++) v[i].clear(); while (!q.empty()) q.pop(); cnt=0; } void Floyed() { for (int k=1;k<=n;k++) for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) if (i!=j && j!=k && i!=k) f[i][j]=min(f[i][j],f[i][k]+f[k][j]); } void walk(data x) { for (int i=head[x.num];i;i=e[i].next) if (dis[e[i].to][x.w+e[i].w*3]>dis[x.num][x.w]+e[i].w*1000) { dis[e[i].to][x.w+e[i].w*3]=dis[x.num][x.w]+e[i].w*1000; if (!vis[e[i].to][x.w+e[i].w*3]) { q.push((data){e[i].to,x.w+e[i].w*3}); vis[e[i].to][x.w+e[i].w*3]=1; } } } void bus(data x) { for (int i=0;i<(int)v[x.num].size();i++) { int s,p=v[x.num][i]; for (s=1;s<=t[p][0];s++) if (t[p][s]==x.num) break; s++; double D=0; for (s;s<=t[p][0];s++) { D+=d[t[p][s-1]][t[p][s]]; if (dis[t[p][s]][x.w+6]>dis[x.num][x.w]+D*250) { dis[t[p][s]][x.w+6]=dis[x.num][x.w]+D*250; if (!vis[t[p][s]][x.w+6]) { q.push((data){t[p][s],x.w+6}); vis[t[p][s]][x.w+6]=1; } } } } } void taxi(data x) { for (int i=1;i<=n;i++) if (i!=x.num) { int W=x.w+10+(f[x.num][i]>3 ? 2*(f[x.num][i]-3) : 0); if (dis[i][W]>dis[x.num][x.w]+f[x.num][i]*125) { dis[i][W]=dis[x.num][x.w]+f[x.num][i]*125; if (!vis[i][W]) { q.push((data){i,W}); vis[i][W]=1; } } } } void SPFA(int s) { for (int i=1;i<=n;i++) for (int j=0;j<=L;j++) dis[i][j]=inf; dis[s][0]=0; q.push((data){s,0}); while (!q.empty()) { data x=q.front();q.pop(); vis[x.num][x.w]=0; walk(x); bus(x); taxi(x); } } int main() { int Case;scanf("%d",&Case); while (Case--) { scanf("%d%d%d%d%d%d",&L,&n,&m,&S,&T,&B); Init(); for (int uu,vv,ww,i=1;i<=m;i++) { scanf("%d%d%d",&uu,&vv,&ww); link(uu,vv,ww); d[uu][vv]=d[vv][uu]=f[uu][vv]=f[vv][uu]=ww; } for (int i=1;i<=B;i++) { scanf("%d",&t[i][0]); for (int j=1;j<=t[i][0];j++) { scanf("%d",&t[i][j]); v[t[i][j]].push_back(i); } } Floyed(); SPFA(S); int ans=inf; for (int i=0;i<=L;i++) ans=min(ans,dis[T][i]); if (ans==inf) printf("no\n"); else printf("%d\n",ans); } return 0; }
This passage is made by MashiroSky.