【NOIP2012普及组】文化之旅

来源:互联网 发布:军爷捏脸数据 编辑:程序博客网 时间:2024/06/06 06:31

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

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

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

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

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

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

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

AC代码:

#include <iostream>#include <cstdio>#include <queue>#include <cstring>#define min(a,b) (a<b ?a:b)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_queue<node>Q;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].w<dist[edge[i].v]){                dist[edge[i].v]=w+edge[i].w;                Q.push(node(edge[i].v,dist[edge[i].v]));            }        }        visited[u]=true;    }}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]<ans) //最优性剪枝            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);  //从起点开始dfs    if (ans!=INF) cout<<ans<<endl; else cout<<-1<<endl;    return 0;}