校内赛题解:P1078 [NOIP2012 普及组] 文化之旅
T4 题目传送门
思路
一道最短路问题。不会最短路算法的同学可以先去这里学习一下。
由于 CCF 会卡 spfa(本题没卡),故我们选择 dijstrka 算法进行求解。由于题目中要求不能重复学习一个文化且有些文化不被“包容”,那么我们选择用 set 记录从
这个程序的时间复杂度为
代码
#include<bits/stdc++.h>
#define ll long long
#define pb push_back
#define pii pair<int,int>
#define fi first
#define se second
using namespace std;
ll read(){//快读优化,不加也行。
ll k=0;bool flag=1;char c=getchar();
while(c>'9'||c<'0'){if(c=='-')flag=0;c=getchar();}
while(c>='0'&&c<='9'){k=(k<<1)+(k<<3)+(c^48);c=getchar();}
if(flag)return k;return -k;
}
const int N=110;
int n,k,m,s,t,c[N],dis[N];
bool a[N][N];
vector<pii>g[N];
struct node{
int step,x;
set<int>st;
bool operator<(const node a)const{return step>a.step;}//优先队列需要定义结构体的排序方式。记得是大根堆,所以符号反着写。
};priority_queue<node>q;
bool check(set<int>st,int now){//判断学习过的文化是否满足到达这个城市。
for(int i=1;i<=k;++i){
if(!a[now][i])continue;//没有要求不能进入。
if(st.find(i)!=st.end())return 0;//要求不能进入且学习过这个文化,就到达不了。
}
return 1;//不是不能到达就是可以到达。
}
int main(){
cin>>n>>k>>m>>s>>t;
for(int i=1;i<=n;++i)c[i]=read();
for(int i=1;i<=k;++i){
for(int j=1;j<=k;++j)a[i][j]=read();
}
for(int i=1;i<=m;++i){
int u=read(),v=read(),w=read();
g[u].pb({w,v});//双向建边。
g[v].pb({w,u});
}
memset(dis,0x3f,sizeof dis);//记得初始化最大值。
dis[s]=0;
set<int>st;
st.insert(c[s]);
q.push({0,s,st});
while(q.size()){
node now=q.top();
q.pop();
for(auto i:g[now.x]){
if(dis[i.se]>dis[now.x]+i.fi){//如果不是最短路径再判断。
if(st.find(c[i.se])==st.end()&&check(now.st,c[i.se])){//还要判断不能重复学习一种文化(&& 号前的部分)。
dis[i.se]=dis[now.x]+i.fi;//更新到达这个点的最短路。
now.st.insert(c[i.se]);//学习这个文化。
q.push({dis[i.se],i.se,now.st});
now.st.erase(c[i.se]);//“忘掉”这个文化,便于遍历其他城市。
}
}
}
}
if(dis[t]==0x3f3f3f3f)cout<<-1;//走不通输出 -1。
else cout<<dis[t];
return 0;
}
AC 记录