L3-011 直捣黄龙 (30 分) (dijkstra+map)
这几天写了一些复杂的最短路的题,发现这些题都是有规律的,掌握了这些规律,任何一道最短路的题将不在话下 -
基本思路
这题变化就在于每个点不是数是一个字符串,既然这样我们转化为数就好啦。这里我想到了map容器,我们将这些据点的值从0-n-1编号,作为map[i],那么它的下标就是所对应的字符串了。然后进行dijkstra的时候先判断最短的路径,然后是节点数,再就是歼敌数了,这些都可以按照套路来了,把这个多重判断记下来其它题也就so easy了。
废话不多说直接上代码
#include<iostream>
#include<string>
#include<cstdio>
#include<cstring>
#include<map>
using namespace std;
const int inf=0x3f3f3f3f;
int d[500][500],vis[500],dis[500];
int path[500]; //记录路径
int cnt[500]; //记录最短路径数
int ret[500]; //记录经过的据点数
int sum[500],aa[500]; //到达一据点能歼敌总数、每个据点歼敌数
int dd; //记录终点
int n;
map<string,int> m;
void dfs(int k)
{
if(k==0)
{
map<string,int>::iterator it;
for(it=m.begin();it!=m.end();++it)
{
if(it->second==k){
cout<<it->first;break;
}
}
return;
}
dfs(path[k]);
cout<<"->";
map<string,int>::iterator it;
for(it=m.begin();it!=m.end();++it)
{
if(it->second==k){
cout<<it->first;break;
}
}
}
void dijkstra(int s)
{
memset(dis,inf,sizeof(dis));
dis[s]=0;
cnt[s]=1;
for(int i=0;i<n;++i)
{
int t=-1,minn=inf;
for(int j=0;j<n;++j)
if(!vis[j]&&dis[j]<minn){
t=j;
minn=dis[j];
}
vis[t]=1;
if(t==-1)
break;
for(int j=0;j<n;++j)
{
if(!vis[j]&&(dis[j]>dis[t]+d[t][j])){
dis[j]=dis[t]+d[t][j];
sum[j]=sum[t]+aa[j];
path[j]=t;
ret[j]=ret[t]+1;
cnt[j]=cnt[t];
}
else if(!vis[j]&&dis[j]==dis[t]+d[t][j])
{
cnt[j]+=cnt[t];
if(ret[j]<ret[t]+1)
{
ret[j]=ret[t]+1;
path[j]=t;
sum[j]=sum[t]+aa[j];
}
else if(ret[j]==ret[t]+1&&sum[j]<sum[t]+aa[j])
{
path[j]=t;
sum[j]=sum[t]+aa[j];
}
}
}
}
}
int main()
{
memset(d,inf,sizeof(d));
for(int i=0;i<n;++i)
d[i][i]=0;
int k,b;
cin>>n>>k;
string a,c;
getchar();
cin>>a>>c;
m[a]=0;
for(int i=1;i<n;++i)
{
cin>>a>>b;
if(a==c)
dd=i;
m[a]=i;
aa[i]=b;
}
while(k--)
{
cin>>a>>c>>b;
d[m[a]][m[c]]=d[m[c]][m[a]]=b;
}
dijkstra(0);
dfs(dd);
cout<<endl;
cout<<cnt[dd]<<" "<<dis[dd]<<" "<<sum[dd];
}