ps: 这里小镇就是城市,n个城市,题目里的5个小镇没用的。
输入:
5 5
Orz
Ada Aed 5
Orz Ada 6
Apq Aed 8
Akk Apq 12
Aed Orz 3
输出:
28
思路: 核心:最小生成树
题目里说走回头路的话,花费为0,求将所有城市遍历的最小花费。既然花费为0,相当于无代价回溯,只需求图的最小生成树即可。
城市名用map存,字符串转化为编号更舒服。
//
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
map <string ,int> mm; //城市名和int对应
int head[5010];
int tot=0;
int cnt=0;
ll dis[5010];//存每个点离树的最近距离
int v[5010]; //最近距离是否已确定
int st; //起点
ll res=0; //结果
struct ty
{
int t,next;
int l;
bool operator < (const ty &b ) const //prim算法,将花费最小的边存前面
{
return l > b.l;
}
}edge[4000010];
priority_queue <ty > q;
void addedge(int x, int y,int z)
{
edge[++tot].t=y;
edge[tot].l=z;
edge[tot].next=head[x];
head[x]=tot;
}
void prim()
{
ty ty3;
ty3.l=0;
ty3.t=st;
q.push(ty3);
dis[st]=0;
while( !q.empty() )
{
ty ty1=q.top();
q.pop();
if( v[ty1.t] ) continue;
v[ty1.t]=1;
res+=ty1.l;
dis[ty1.t]=0;
for(int i=head[ty1.t] ;i!=-1 ;i=edge[i].next)
{
int u=edge[i].t;
if(edge[i].l <dis[u] )
{
dis[u] =edge[i].l;
ty ty2;
ty2.t=u;
ty2.l=dis[u];
q.push(ty2);
}
}
}
}
int main()
{
ios::sync_with_stdio(false );
// cin.tie(0);cout.tie(0);
int n,qq;
while( cin>>n>>qq)
{
//初始化各种数据和结构
memset(dis,0x3f,sizeof(dis));
memset(head,-1,sizeof(head));
memset(edge,-1,sizeof(edge));
memset(v,0,sizeof(v));
tot=0,cnt=0,res=0;
mm.clear();
while(!q.empty() ) q.pop();
int flag=0;
//输入起点
string o;
cin>>o;
for(int i=1 ;i<=qq; i++)
{
string s1,s2;
int z;
cin>>s1>>s2;
cin>>z;
//将城市名转为编号存图
if( mm.find(s1) ==mm.end() ) mm[s1]=++cnt;
if( mm.find(s2) ==mm.end() ) mm[s2]=++cnt;
int x=mm[s1];
int y=mm[s2];
addedge(x,y,z);
addedge(y,x,z);
}
st=mm[o];//找起点
if( n==1 ) {cout<<0<<"\n";continue;} //n==1特判
//prim算法求最小生成树
prim();
//判是不是每个城市都走过了
for(int i=1 ;i<=n ;i++)
{
if( !v[i] ) {cout<<"No!\n";flag=1;break;}
}
if(flag) continue;
cout<<res<<endl;
}
}