Hdu 2923(最短路)

hdu 2923

 

思路:
从修理厂到各个修车地点的距离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;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值