http://acm.timus.ru/problem.aspx?space=1&num=1085
题目
K个好朋友要庆祝他们在程序设计大赛夺得第一名。但是电车票却涨价了,他们住在城市的不同地方,他们需要选择一个电车站作为集合地点,又希望坐电车花的钱尽量少。你需要设计一个程序帮助他们选择集合地点。
城市里面有M个电车运行路线(他们只会坐电车,因为太远了)。每条路线经过的站点都已知。对于每个人我们知道他有多少钱、他是否有月卡(也就是坐电车不花钱)。一张电车票要4卢布(一张票整条电车运行路线通行,也就是说路线的站点间通勤一次只要4卢布)。
你需要挑出一个电车站作为集合地点,满足每个人不会用超出他自己的零花钱(他们之间不会相互借钱),并使得他们的总花销最小。如果一个人要换乘一次,就要另外购买一张票票乘坐其他路线的电车。
输入
第一行两个整数
N,M(1≤N,M≤100)
,分别表示站点数和路线数。接下来M行每行第一个整数
L(2≤L≤100)
表示该条路线会经过多少个站点,同一行接下来跟着
L
个整数表示该条路线会经过哪些站点(站点标号1~N)。
接下来一行一个整数
输出
输出一行,如果存在一个站点使得每个人自己的钱足够买电车票到选定的集合地点,输出2个整数分别为集合地点和最小的总花费(如果有多个集合地点可选,随便输出一个)。
如果不存在输出一行一个数0。
样例输入
4 3
2 1 2
2 2 3
2 3 4
3
27 1 0
15 4 0
45 4 0
样例输出
4 12
题解
显然本题是多源最短路径,上Floyd。
由于一条路线上的所有站点间到一次都是4卢布,因此我们在初始化邻接矩阵的时候相当于构造了一个完全子图。然后跑一边floyd。
枚举每个站点设为集合地点,那么枚举每个人判断一下就好了。
打比赛的时候有人INF加爆了。。这个问题要注意。
#include <cstdio>
#include <cstring>
#define FOR(i,j,k) for(i=j;i<=k;++i)
const int inf = 0x3f3f3f3f;
const int N = 110;
int ruble[N], from[N], hasTicket[N];
int stop[N], f[N][N];
int n, k;
void floyd() {
int i, j, k;
FOR(k,1,n) FOR(i,1,n) FOR(j,1,n)
if (f[i][k] != inf && f[k][j] != inf &&
f[i][j] > f[i][k] + f[k][j])
f[i][j] = f[i][k] + f[k][j];
}
int main() {
int m, l, i, j, mi = inf, p, c;
scanf("%d %d", &n, &m);
memset(f, 0x3f, sizeof f);
FOR(i,1,n) f[i][i] = 0;
while (m--) {
scanf("%d", &l);
FOR(i,1,l) scanf("%d", &stop[i]);
FOR(i,1,l) FOR(j,i+1,l)
f[stop[i]][stop[j]] = f[stop[j]][stop[i]] = 4;
}
scanf("%d", &k);
FOR(i,1,k) scanf("%d%d%d", &ruble[i], &from[i], &hasTicket[i]);
floyd();
FOR(i,1,n) {
c = 0;
FOR(j,1,k) {
if (f[i][from[j]] == inf || !hasTicket[j] && f[i][from[j]] > ruble[j]) {
c = inf;
break;
}
if (!hasTicket[j])
c += f[i][from[j]];
}
if (mi > c) {
mi = c;
p = i;
}
}
if (mi == inf) puts("0");
else printf("%d %d\n", p, mi);
return 0;
}