湫湫系列故事——过年回家
Time Limit: 500/200 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)Total Submission(s): 1193 Accepted Submission(s): 254
Problem Description
出门在外,最想念的还是家,对在深圳腾讯工作的HR湫湫来说,春节回家是一年中最期盼的事,不仅可以见到阔别已久的亲人,还能以相亲的名义调侃众多帅哥(她的内心告诉她:如果相亲能遇到参加过腾讯编程马拉松的同学,就直接把自己嫁了~)。
同时,每年的春节湫秋也都会纠结一把,因为车票实在是太难抢了,不过2013的春节有点特殊,作为一个曾经的ACMer,湫湫制作出了很完美的刷票机,也就是说她再也不用担心买不上票了,但是想来想去还是觉得随便买票实在是浪费了辛辛苦苦搞出来的刷票机,所以她决定要用最舒适的方式回家。
假设湫湫有可能经过的n个城市分别编号从1到n,湫湫要从城市A回到城市B,购票网站上列出了t辆列车行程,每辆车的行程用一个字符串表示,途径的城市间用+号相连,如1+2+3+5代表一辆从1城市分别经过2,3到达5的火车,湫湫可以从中间任意一站出发和下车(路径是单向的,即必须沿字符串从左到右来走),每个字符串对应着一个整数k,k=0表示该车只有硬座,k=1表示该车有卧铺也有硬座,在整个回家的计划中,同一辆车可以坐无限次,为了中途换车的方便,如果在起点坐的是卧铺,则后面乘坐的车必须全是卧铺,同样的,如果在起点坐的是硬座,则后面乘坐的车必须全是硬座,假设一段(一辆车行程中,两相邻城市间为一段)硬座的不舒适度是D1,一段卧铺的不舒适度是D2,求湫湫回家最小的不舒适度。
同时,每年的春节湫秋也都会纠结一把,因为车票实在是太难抢了,不过2013的春节有点特殊,作为一个曾经的ACMer,湫湫制作出了很完美的刷票机,也就是说她再也不用担心买不上票了,但是想来想去还是觉得随便买票实在是浪费了辛辛苦苦搞出来的刷票机,所以她决定要用最舒适的方式回家。
假设湫湫有可能经过的n个城市分别编号从1到n,湫湫要从城市A回到城市B,购票网站上列出了t辆列车行程,每辆车的行程用一个字符串表示,途径的城市间用+号相连,如1+2+3+5代表一辆从1城市分别经过2,3到达5的火车,湫湫可以从中间任意一站出发和下车(路径是单向的,即必须沿字符串从左到右来走),每个字符串对应着一个整数k,k=0表示该车只有硬座,k=1表示该车有卧铺也有硬座,在整个回家的计划中,同一辆车可以坐无限次,为了中途换车的方便,如果在起点坐的是卧铺,则后面乘坐的车必须全是卧铺,同样的,如果在起点坐的是硬座,则后面乘坐的车必须全是硬座,假设一段(一辆车行程中,两相邻城市间为一段)硬座的不舒适度是D1,一段卧铺的不舒适度是D2,求湫湫回家最小的不舒适度。
Input
输入数据的第一行包含一个整数Q,表示测试数据的组数;
每组数据的第一行是2个正整数n和t,分别表示城市数和列车数;
接下来t行,每行一个字符串表示列车行程,字符串长度小于10000,每个字符串后跟一个整数k(k为0或1),之间用空格隔开;
接下来一行是D1,D2,其含义见题目描述;
最后一行是2个正整数A和B,表示起始和终点城市。
[Technical Specification]
1 <= Q <= 100
1 < n <= 200
1 < t <= 1000
0 < D1 <= 10000, 0 < D2 <= 10000,D1和D2的大小关系不确定
1 <= A, B <= n 且 A <> B
每组数据的第一行是2个正整数n和t,分别表示城市数和列车数;
接下来t行,每行一个字符串表示列车行程,字符串长度小于10000,每个字符串后跟一个整数k(k为0或1),之间用空格隔开;
接下来一行是D1,D2,其含义见题目描述;
最后一行是2个正整数A和B,表示起始和终点城市。
[Technical Specification]
1 <= Q <= 100
1 < n <= 200
1 < t <= 1000
0 < D1 <= 10000, 0 < D2 <= 10000,D1和D2的大小关系不确定
1 <= A, B <= n 且 A <> B
Output
对于每组数据,如果湫湫可以到达目的地,则输出一个整数,表示湫湫到家所需的最小不舒适度。如果不能到达则直接输出-1。
Sample Input
1 6 5 2+4+3+5+1+6 1 5+4+2+3+1 1 3+2+5+1+6 1 6+2 0 6+3+1+4+5+2 0 3 2 5 3Sample Output4#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> //第一次提交WA,确实,为什么给了例子的答案是4 //其实自己做的是对的,只是自己结果打错了,一定要小心,自己是会做的第二次还是WA,有点疑惑了,为什么呢? //应该还是错在解析城市这一步,之前只试过解析1~9范围内的城市,没有解析过2位数3位数的城市 //最终AC //我想说这道题拿到手题目意思懂,但是为什么给的例子的答案是4,这个不懂。。。卧铺5->4,4->3 //k=0表示只有硬座,这个要弄好了 //想到是用dijkstra算法来做 #define MAXINT 10005 #define MAXN 205 #define INFINT 100000 //也要注意这个最大值,不能随便出,因为我最后打印是2个或,*的话容易翻转,要不就老老实实的多写几个if int n = 0; int p = 0; int D1 = 0; int D2 = 0; int start = 0; int end = 0; int pathnum = 0; char str[MAXINT]; int path[MAXN][MAXN][2]; //0--表示卧铺,1--表示硬座 int visit[MAXN][2]; int dis[MAXN][2]; //表示从起点到各个点的最短距离,0--表示卧铺,1--表示硬座 int strlen() { int size = 0; int i = 0; while (str[size] != '\0') { size++; } return size; } void parsess(int k) { int i = 0; int j = 0; int size = 0; int x1 = 0; int x2 = 0; size = strlen(); int plus[1000]; int num = 0; int kk = 0; for (i = 0; i < size;i++) { if ('+' == str[i]) { plus[num++] = i; //保存所有+的位置 } } for (i = 0; i < num;i++) { kk = 0; x1 = 0; x2 = 0; //解析起点 if (0 == i) { for (j = 0; j <= plus[i] - 1; j++) { x1 = x1*10 + (str[j] - '0') ; //kk++; } } else { for (j = plus[i - 1]+1; j <= plus[i] - 1; j++) { x1 = x1 * 10 + (str[j] - '0'); //kk++; } } //解析终点 kk = 0; if (i == (num-1)) { //最后一个点 for (j = plus[i]+1; j <= (size - 1); j++) { x2 = x2 * 10 + (str[j] - '0'); //kk++; } } else { for (j = plus[i] + 1; j <= plus[i + 1] - 1; j++) { x2 = x2 * 10 + (str[j] - '0'); //kk++; } } if (1 == k) //卧铺硬座都有 { path[x1][x2][0] = 1; path[x1][x2][1] = 1; } else { path[x1][x2][1] = 1; //k=0表示只有硬座 } } return; } void initstring() { int i = 0; for (i = 0; i < MAXINT;i++) { str[i] = '\0'; } return; } void init() { int i = 0; int j = 0; int k = 0; for (i = 0; i < MAXINT; i++) { str[i] = '\0'; } for (i = 0; i < MAXN; i++) { for (j = 0; j < MAXN; j++) { for (k = 0; k < 2; k++) { path[i][j][k] = INFINT; visit[j][k] = 0; dis[j][k] = INFINT; } } } pathnum = 0; return; } void dijsktra() { int i = 0; int j = 0; int prev = 0; int min = INFINT; dis[start][0] = 0; dis[start][1] = 0; visit[start][0] = 1; visit[start][1] = 1; for (i = 1; i <= n;i++) { for (j = 0; j < 2;j++) { if (1 == path[start][i][j]) { dis[i][j] = 1; } } } //求卧铺 for (i = 1; i <= n;i++) { min = INFINT; //先找出最短的一个点 for (j = 1; j <= n;j++) { if ((min>dis[j][0]) && (0 == visit[j][0])) { min = dis[j][0]; prev = j; } } visit[prev][0] = 1; //更新各个点的距离,根据min for (j = 1; j <= n; j++) { if ((dis[j][0] > (dis[prev][0] + path[prev][j][0])) && (0 == visit[j][0])) { dis[j][0] = dis[prev][0] + path[prev][j][0]; } } } //求硬座 for (i = 1; i <= n; i++) { min = INFINT; //先找出最短的一个点 for (j = 1; j <= n; j++) { if ((min>dis[j][1]) && (0 == visit[j][1])) { min = dis[j][1]; prev = j; } } visit[prev][1] = 1; //更新各个点的距离,根据min for (j = 1; j <= n; j++) { if ((dis[j][1] > (dis[prev][1] + path[prev][j][1])) && (0 == visit[j][1])) { dis[j][1] = dis[prev][1] + path[prev][j][1]; } } } return; } int main() { int i = 0; int j = 0; int T = 0; int k = 0; freopen("input.txt","r",stdin); scanf("%d",&T); for (i = 0; i < T;i++) { scanf("%d %d",&n,&p); init(); for (j = 0; j < p;j++) { initstring(); scanf("%s",&str[0]); scanf("%d",&k); parsess(k); } scanf("%d %d",&D1,&D2); scanf("%d %d", &start, &end); dijsktra(); if ((INFINT != dis[end][0]) || (INFINT != dis[end][1])) { printf("%d\n", ((dis[end][0] * D2) > (dis[end][1] * D1)) ? (dis[end][1] * D1) : (dis[end][0] * D2)); } else { printf("-1\n"); } } return 0; }