题目大意:路上一共有三种风景点A,B,C,然后从1号点出发经过至少一个B和C类风景点,再回到1号点,然后问最短路径是多少?
首先有3种风景点,因此对应就有8种状态(状态表示的是到某个点经过的风景点有哪些),到每个点都有8种状态,记录状态的话用的是dis数组的第二维(将第二维j转化为一个二进制数对应有3位,第一位表示的是A类风景点的状态,第二位表示的是B类风景点的状态,第三位表示的是C类风景点的状态,对应的数位若是1表示有经过,0表示没经过),定义dis[i][j]表示在j状态下到达i号点的最短路径,然后就用dij递推出dis[1][7]和dis[1][6](7表示的状态是111,6表示的状态是110,都是经过了B,C风景点的),挑个最小的即可。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=200010;
ll inf=1e15;
struct node
{
int v;
ll w;
node(int vv=0,ll ww=0)
{
v=vv;
w=ww;
}
};
struct state
{
int v,sta;
ll d;
state(int vv=0,int staa=0,ll dd=0)
{
v=vv;
sta=staa;
d=dd;
}
friend bool operator <(const state&a,const state&b)
{
return a.d>b.d;
}
};
vector<node>g[maxn];
ll dis[maxn][10];//dis[i][j]表示j状态下到达i节点的最短路径
int vis[maxn][10],val[maxn],n,m;
void dij()
{
for(int i=1;i<=n;i++)
for(int j=0;j<=8;j++)
dis[i][j]=inf,vis[i][j]=0;
dis[1][1<<val[1]]=0;
priority_queue<state>q;
while(!q.empty()) q.pop();
q.push(state(1,1<<val[1],0));
while(!q.empty())
{
state now=q.top();
q.pop();
int u=now.v,sta=now.sta;
if(vis[u][sta]) continue;
vis[u][sta]=1;
for(int i=0;i<g[u].size();i++)
{
int v=g[u][i].v,nxtsta=sta|(1<<val[v]);
ll w=g[u][i].w;
if(!vis[v][nxtsta]&&dis[v][nxtsta]>(dis[u][sta]+w))
{
dis[v][nxtsta]=dis[u][sta]+w;
q.push(state(v,nxtsta,dis[v][nxtsta]));
}
}
}
}
int main()
{
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&val[i]);
}
while(m--)
{
int u,v;
ll d;
scanf("%d %d %lld",&u,&v,&d);
g[u].push_back(node(v,d));
g[v].push_back(node(u,d));
}
dij();
printf("%lld
",min(dis[1][7],dis[1][6]));
return 0;
}