http://acm.hdu.edu.cn/showproblem.php?pid=6386
题意:
找到从1到n的最小花费,如果路径的相邻的两个ci,不一样就增加一个花费
分析:
用bfs找出从1到n的最小花费,只需要将需要更新的加入队列,然后乱搞,然后优化,否则容易tle
代码:
#include<bits/stdc++.h>
using namespace std;
int head[110005],n,m,cnt,ans,dep[110005];
vector<int>h[110005];
vector<int>::iterator it;
struct node
{
int father;//上一段的ci
int num,val;//num为从1到该节点的花费 val为该节点的ci
int id,fatherid;//该节点的名字 父亲节点的名字
int ppo;
bool operator<(const node &aa)const
{
if(num!=aa.num)
return num>aa.num;
return ppo>aa.ppo;//如果出现连续段的相同ci段,则不全部更新,以免多次重复不必要的更新
}
};
struct Node
{
int to,next,val;
}v[200100<<1];
void init()
{
cnt=0;
int i;
for(i=0;i<=n;i++)
head[i]=-1,dep[i]=800005,h[i].clear();
ans=800005;
}
void add(int from,int to,int val)
{
v[cnt].to=to;
v[cnt].next=head[from];
v[cnt].val=val;
head[from]=cnt;
cnt++;
v[cnt].to=from;
v[cnt].next=head[to];
v[cnt].val=val;
head[to]=cnt;
cnt++;
}
void bfs()
{
priority_queue<node>q;
int i;
node now,sec;
dep[1]=0;
now.id=1;
now.num=0;
now.father=-1;
now.fatherid=-1;
now.val=-1;
now.ppo=0;
q.push(now);
int minx;
minx=800005;
while(!q.empty())
{
now=q.top();
q.pop();
if(now.id==n&&ans>now.num)
{
ans=now.num;
}
if(now.num>dep[now.id])continue;
if(now.num>=dep[n])break;
for(i=head[now.id];i!=-1;i=v[i].next)
{
sec.father=now.val;
sec.id=v[i].to;
sec.val=v[i].val;
sec.num=now.num;
sec.fatherid=now.id;
if(v[i].to==now.fatherid)continue;
sec.ppo=now.ppo+1;
if(sec.father!=sec.val)
sec.num++;
if(sec.id==n&&ans>sec.num)
{
ans=now.num;
}
if(sec.num<dep[sec.id])
dep[sec.id]=sec.num,q.push(sec),h[sec.id].clear(),h[sec.id].push_back(sec.val);
else
if(sec.num==dep[sec.id])
{
it=find( h[sec.id].begin( ), h[sec.id].end( ),sec.val);
if(it==h[sec.id].end())
dep[sec.id]=sec.num,q.push(sec),h[sec.id].push_back(sec.val); //如果更新的花费的路径的ci没有出现过,就加入该结点的数组
}
}
}
return;
}
int main()
{
int i,j,aa,bb,cc;
while(~scanf("%d%d",&n,&m))
{
init();
for(i=0;i<m;i++)
{
scanf("%d%d%d",&aa,&bb,&cc);
if(aa==bb)continue;
add(aa,bb,cc);
}
bfs();
if(dep[n]==800005)
printf("-1\n");
else
printf("%d\n",dep[n]);
}
}