题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2923
题目意思:有n个城市,城市是用字符串表示的,c个城市有坏的车,r条有向有权道路,求从你在所在的城市,将坏的车拖回来的花费。
思路:思路蛮简单,就是用map将城市(字符串)转化成编号,再求最短路,就是map处理稍微复杂点。
开始我没仔细看数据大小,用spfa做的,代码量较多,但都是重复的代码,要正向建图求到坏车的花费,在反向建图求回来的花费。而用floyd就不用了,正常求就行。
但是这题坑点是真的多,都快被坑哭了。我先列列坑点:
1.一个城市可能有很多辆坏的车, 所以需要用一个数组存储坏车所在城市。
2.一次只能拖一辆车。。。。一点也不符合实际,拖车店要亏死。
3.两个城市间会有n条路,用前向星储存的还好,有数组存的可能就错了,还要比较,存最短的路。
还有记得每次清除map。
spfa:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<queue> #include<map> #define inf 0x3f3f3f3f using namespace std; typedef long long ll; const int maxn=1e6+10; map<string,int>m; struct node{ int u,v,w,next; }edge1[maxn],edge2[maxn]; int head1[maxn],head2[maxn],visit[maxn]; int d1[maxn],d2[maxn],cnt1,cnt2; int n,c,r,ans,aim[maxn]; void init(){//初始化 m.clear(); memset(head1,-1,sizeof(head1)); memset(head2,-1,sizeof(head2)); memset(d1,0x3f,sizeof(d1)); memset(d2,0x3f,sizeof(d2)); memset(aim,0,sizeof(aim)); cnt1=cnt2=ans=0; } void add1(int u,int v,int w){//正向建图连边 edge1[cnt1].v=v; edge1[cnt1].w=w; edge1[cnt1].next=head1[u]; head1[u]=cnt1++; } void add2(int u,int v,int w){//反向建图连边 edge2[cnt2].v=v; edge2[cnt2].w=w; edge2[cnt2].next=head2[u]; head2[u]=cnt2++; } void spfa1(){// 求到坏车的花费 queue<int>q; memset(visit,0,sizeof(visit)); q.push(aim[1]); d1[aim[1]]=0; visit[aim[1]]=1; while(!q.empty()){ int u=q.front(); q.pop(); visit[u]=0; for(int i=head1[u];i!=-1;i=edge1[i].next){ int v=edge1[i].v; int w=edge1[i].w; if(d1[v]>d1[u]+w){ d1[v]=d1[u]+w; if(!visit[v]){ visit[v]=1; q.push(v); } } } } } void spfa2(){//求回来的花费 queue<int>q; memset(visit,0,sizeof(visit)); q.push(aim[1]); d2[aim[1]]=0; visit[aim[1]]=1; while(!q.empty()){ int u=q.front(); q.pop(); visit[u]=0; for(int i=head2[u];i!=-1;i=edge2[i].next){ int v=edge2[i].v; int w=edge2[i].w; if(d2[v]>d2[u]+w){ d2[v]=d2[u]+w; if(!visit[v]){ visit[v]=1; q.push(v); } } } } } int main(){ std::ios::sync_with_stdio(false); int k=1; while(cin>>n>>c>>r&&(n||c||r)){ init(); string s,s1,s2; int num=1; for(int i=1;i<=c+1;i++){ cin>>s; if(!m[s]) m[s]=num++; aim[i]=m[s];//用 aim存每个坏车所在城市的编号 } for(int i=0;i<r;i++){//map处理路的关系。 cin>>s>>s1>>s2; if(!m[s])//记得这里要写 m[s]=num++; if(!m[s2]) m[s2]=num++; int len=s1.size(),w=0; for(int j=0;j<len;j++){ if(s1[j]>='0'&&s1[j]<='9') w=w*10+s1[j]-'0'; } if(s1[0]=='<'){ add1(m[s2],m[s],w);//正向建图 add2(m[s],m[s2],w);//方向建图 } if(s1[len-1]=='>'){ add1(m[s],m[s2],w); add2(m[s2],m[s],w); } } spfa1(); spfa2(); for(int i=2;i<=c+1;i++) ans+=d1[aim[i]]+d2[aim[i]]; cout<<k++<<". "<<ans<<endl; } return 0; }
floyd:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<queue> #include<map> #define inf 0x3f3f3f3f using namespace std; typedef long long ll; const int maxn=1e3+100; map<string,int>m; int mp[maxn][maxn],aim[maxn]; int n,c,r,ans; void init(){//初始化 m.clear();//记得每次清除map memset(mp,0x3f,sizeof(mp)); memset(aim,0,sizeof(aim)); } void floyd(){//floyd求最短路 for(int k=1;k<=n;k++) for(int i=1;i<=n;i++) for(int j=1;j<=n;j++){ if(mp[i][j]>mp[i][k]+mp[k][j]) mp[i][j]=mp[i][k]+mp[k][j]; } } int main(){ std::ios::sync_with_stdio(false); int k=1; while(cin>>n>>c>>r&&(n||c||r)){ init(); ans=0; string s,s1,s2; int num=0; for(int i=1;i<=c+1;i++){ cin>>s; if(!m[s]){ m[s]=++num; } aim[i]=m[s];//aim储存城市编号 } for(int i=0;i<r;i++){ cin>>s>>s1>>s2; if(!m[s]) m[s]=++num; if(!m[s2]) m[s2]=++num; int len=s1.size(),w=0; for(int j=0;j<len;j++){ if(s1[j]>='0'&&s1[j]<='9') w=w*10+s1[j]-'0'; } if(s1[0]=='<'){ mp[m[s2]][m[s]]=min(mp[m[s2]][m[s]],w);//记得取最小的边 } if(s1[len-1]=='>'){ mp[m[s]][m[s2]]=min(mp[m[s]][m[s2]],w); } } floyd(); for(int i=2;i<=c+1;i++) ans+=mp[aim[1]][aim[i]]+mp[aim[i]][aim[1]]; cout<<k++<<". "<<ans<<endl; } return 0; }