题解:P1078 [NOIP2012 普及组] 文化之旅

· · 题解

提示:由于测试数据过水,可以通过此题的程序不一定完全正确。如果我的程序出现问题,欢迎 hack。

Solution P1078

Idea

看到最少,就想到使用 dijstkra 算法。

但是这道题不同的一点是,这里面出现了文化歧视,文化不重复学习等。我们一定需要在算法内加入状态的标记,才有可能满足条件。

于是我们在算法中加入一个数组 use,记录这种文化的点是否可以被遍历。

代码细节较多,具体问题看代码具体分析。 ### Code 开头一堆定义,这个没什么好说的。 ``` #include<bits/stdc++.h> using namespace std; struct edge{ int u,v,w,nxt; }e[10005]; int head[105],cnt,cul/*culture-文化*/[105],qs/*歧视*/[105][105]; long long dis[105]; bool vis[105]; int n,m,s; int k,t; void add(int u,int v,int w){ e[++cnt].u=u; e[cnt].v=v; e[cnt].w=w; e[cnt].nxt=head[u]; head[u]=cnt; } long long read() { int f=1,x=0; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-')f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=x*10+ch-'0'; ch=getchar(); } return f*x; } ``` dijstkra 的前置准备部分。 ``` struct node{ int dis,pos; int use[105];//use[i] 表示 i 这一种文化的点是否可以被遍历 bool operator <(const node &x)const{ return x.dis<dis; }//优先队列重载运算符 }; priority_queue<node>q; node p; ``` dijstkra 部分。 ``` void dj(){ p.dis=0; p.pos=s; for(int i=1;i<=k;i++)p.use[i]=0; q.push(p); while(!q.empty()){ node tmp=q.top(); q.pop(); int x=tmp.pos,y=tmp.dis; if(vis[x]||tmp.use[cul[x]])continue; vis[x]=1; tmp.use[cul[x]]=1; for(int i=1;i<=k;i++){ if(qs[cul[x]][i])tmp.use[i]=1;//歧视的打上标记 } for(int i=head[x];i;i=e[i].nxt){ int v=e[i].v; if(tmp.use[cul[v]])continue; if(dis[v]>dis[x]+e[i].w){//松弛 dis[v]=dis[x]+e[i].w; if(!vis[v]){//状态更新,塞进优先队列里 p.dis=dis[v]; p.pos=v; for(int j=1;j<=k;j++){ p.use[j]=tmp.use[j]; } q.push(p); } } } } } ``` 主函数部分。 ``` int main(){ n=read(); k=read(); m=read(); s=read(); t=read(); for(int i=1;i<=n;i++){ cul[i]=read(); dis[i]=1145141919810;//初始设成极大值 } for(int i=1;i<=k;i++){ for(int j=1;j<=k;j++){ qs[j][i]=read(); } } for(int i=1;i<=m;i++){ int u,v,w; u=read(); v=read(); w=read(); add(u,v,w); add(v,u,w); } dis[s]=0; dj(); if(dis[t]!=1145141919810)printf("%lld",dis[t]); else printf("-1"); return 0; } ```