【NOIP2012普及组】文化之旅

这题看起来是一道最短路的题,实际上单纯的最短路不法判断下一个到达的点有没有和以前走过的任何一点冲突。

但是因为数据太弱,裸地最短路算法好像也能过。

实际上这题的正解应该是:最短路预处理+深搜/宽搜

看完数据范围后发现两点间距离值为整数,所以可以用Dijkstra+堆优化从终点跑最短路。

再从起点跑个搜索就可以了,check函数用来判断是否有文化冲突

在dfs时可以用最优性剪枝,如果当前距离D+之前走过的距离+到重点的距离大于以求出的最优值,这种情况应被剪枝

存图的方式是用数组模拟邻接表。

AC代码:

#include #include #include #include #define min(a,b) (a const int INF=0x3f3f3f3f; using namespace std; int n,cul[101],head[101],tot=0,dist[101]; struct node{ //用于优先级队列int pos,w;node(int a,int b){pos=a;w=b;}bool operator < (const node &a)const{ //重载运算符return w>a.w;} }; struct graph{ //存图int v,w,next; }edge[10001]; void add_edge(int u,int v,int w){ //建图edge[++tot]=(graph){v,w,head[u]};head[u]=tot; } priority_queueQ; bool visited[101]; void dij(int m){ //最短路:Dijkstra+堆优化memset(dist,0x3f,sizeof(dist));dist[m]=0;Q.push(node(m,0));while (!Q.empty()){node temp=Q.top();Q.pop();if (visited[temp.pos]) continue;int w=temp.w,u=temp.pos,cur=head[u];for (int i=cur;i;i=edge[i].next){if (w+edge[i].wtrue;} } bool clash[101][101]; //读入文化是否冲突 int been[10001]; //开大一点,记录以来过的文化 int t,k,ans=INF; bool check(int x){ //判断第x种文化是否与之前来过文化冲突for (int i=1;i<=tot;i++)if (clash[been[i]][cul[x]]) return false;return true; } void dfs(int x,int val){ //深搜bool f=false;if (x==t)ans=min(ans,val);if (val>=ans) return;visited[cul[x]]=true;int temp=tot;for (int i=head[x];i;i=edge[i].next){int v=edge[i].v; if (!visited[cul[v]] && !clash[cul[v]][cul[x]] && check(v) && val+edge[i].w+dist[v]//最优性剪枝been[++tot]=cul[v],f=true,dfs(v,val+edge[i].w);}tot=temp; //还原现场if (!f) visited[cul[x]]=false; } int main(){ios::sync_with_stdio(false);int m,s,u,v,d;cin>>n>>k>>m>>s>>t;for (int i=1;i<=n;i++)cin>>cul[i];for (int i=1;i<=k;i++)for (int j=1;j<=k;j++)cin>>clash[i][j];for (int i=1;i<=m;i++){cin>>u>>v>>d;add_edge(u,v,d);add_edge(v,u,d);}dij(n); //从终点开始跑最短路memset(visited,false,sizeof(visited));dfs(s,0); //从起点开始dfsif (ans!=INF) cout<endl; else cout<<-1<<endl;return 0; }


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部