思路:
从修理厂到各个修车地点的距离L1,然后再到修理厂L2,总共c辆坏车,
求∑(L1+L2)的最小值,
可以先正项建图,求出修车厂到各个坏车点的距离L1,
然后逆向建图,求出坏车点到修车厂的最小距离。
注意:
(1)有重边,用邻接表不用考虑,临街矩阵要保证每条边最短
(2)输出的格式,特判时也要注意格式。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<map>
#include<queue>
#include<algorithm>
using namespace std;
const int maxn = 120;
const int INF = 1e9+10;
map <string,int> mp;
int dis[maxn],vis[maxn],n,c,m,a[maxn][maxn],bj[maxn],tot;
struct Node{
int u,v,w,f1,f2;
}cur[maxn*maxn];
void Init(){
for(int i=0;i<=n+5;i++){
for(int j=0;j<=n+5;j++) a[i][j] = INF;
a[i][i] = 0;
}
}
int ID(string ss){
if(!mp.count(ss)){
mp[ss] = ++tot;
return tot;
}
return mp[ss];
}
void spfa(){
for(int i=0;i<=n;i++){
dis[i] = INF;vis[i] = 0;
}
queue <int> q;
q.push(1);dis[1] = 0;
while(!q.empty()){
int x = q.front();q.pop();vis[x] = 0;
for(int i=1;i<=n;i++)
if(a[x][i]!=INF&&dis[x]+a[x][i]<dis[i]){
dis[i] = dis[x]+a[x][i];
if(vis[i]==0){
vis[i] = 1;
q.push(i);
}
}
}
}
int MIN(int x,int y){
return x<y?x:y;
}
int main(void){
int pt = 1;
while(cin>>n>>c>>m&&(n+c+m)){
Init();
mp.clear();tot = 0;
for(int i=0;i<=n+5;i++) bj[i] = 0;
string ss;cin>>ss;ID(ss);
for(int i=1;i<=c;i++){
cin>>ss;bj[ID(ss)]++;
}
for(int i=1;i<=m;i++){
string s1,s2,s3;
cin>>s1>>s2>>s3;
int x = ID(s1),y = ID(s3),z=0,len = s2.length();
cur[i].u = x;cur[i].v = y;
for(int j=0;j<len;j++)
if(s2[j]>='0'&&s2[j]<='9') z = z*10+(s2[j]-'0');
cur[i].w = z;
if(s2[0]=='<'){
a[y][x] = MIN(z,a[y][x]);cur[i].f2 = 1;
}
else cur[i].f2 = -1;
if(s2[s2.length()-1]=='>'){
a[x][y] = MIN(z,a[x][y]);cur[i].f1 = 1;
}
else cur[i].f1 = -1;
}
if(c==0){
printf("%d. 0\n",pt++);
continue;
}
n = tot;
spfa();
long long sum = 0;
for(int i=1;i<=n;i++)
if(bj[i]>0){
sum+=1LL*dis[i]*bj[i];
}
Init();
for(int i=1;i<=m;i++){
int x = cur[i].u,y = cur[i].v,z = cur[i].w;
if(cur[i].f1==1){
a[y][x] = MIN(a[y][x],z);
}
if(cur[i].f2==1){
a[x][y] = MIN(a[x][y],z);
}
}
spfa();
for(int i=1;i<=n;i++)
if(bj[i]>0){
sum+=1LL*dis[i]*bj[i];
}
printf("%d. %lld\n",pt++,sum);
}
return 0;
}