洛谷 P1078 文化之旅 解题报告

P1078 文化之旅

题目描述

有一位使者要游历各国,他每到一个国家,都能学到一种文化,但他不愿意学习任何一种文化超过一次(即如果他学习了某种文化,则他就不能到达其他有这种文化的国家)。不同的国家可能有相同的文化。不同文化的国家对其他文化的看法不同,有些文化会排斥外来文化(即如果他学习了某种文化,则他不能到达排斥这种文化的其他国家)。

现给定各个国家间的地理关系,各个国家的文化,每种文化对其他文化的看法,以及这位使者游历的起点和终点(在起点和终点也会学习当地的文化),国家间的道路距离,试求从起点到终点最少需走多少路。

输入输出格式

输入格式:

第一行为五个整数 \(N,K,M,S,T\),每两个整数之间用一个空格隔开,依次代表国家个数(国家编号为1到\(N\)),文化种数(文化编号为1到\(K\)),道路的条数,以及起点和终点的编号(保证\(S\)不等于\(T\));

第二行为\(N\)个整数,每两个整数之间用一个空格隔开,其中第\(i\)个数\(C_i\),表示国家\(i\)的文化为\(C_i\)

接下来的\(K\)行,每行\(K\)个整数,每两个整数之间用一个空格隔开,记第\(i\)行的第\(j\)个数为\(a_{ij}\),\(a_{ij}=1\)表示文化\(i\)排斥外来文化\(j\)\(i\) 等于$ j\(时表示排斥相同文化的外来人),\)a_{ij}= 0\(表示不排斥(注意\)i\(排斥\)j\(并不保证\)j\(一定也排斥\)i$)。

接下来的\(M\)行,每行三个整数\(u,v,d\) ,每两个整数之间用一个空格隔开,表示国家\(u\)与国家\(v\)有一条距离为\(d\)的可双向通行的道路(保证\(u\)不等于\(v\) ,两个国家之间可能有多条道路)。

输出格式:

一个整数,表示使者从起点国家到达终点国家最少需要走的距离数(如果无解则输出 −1 )。


这道题教会了我一个道理,当数据比较小时,只要复杂度正确,怎么暴力怎么来。

我唯唯诺诺了半天不敢直接写SPFA,最后一写居然就直接过了。

将SPFA中带结构体表示当前点还可以访问的文化,每次进点时多花一个\(O(N)\)处理就行了


#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
const int N=104;
int n,k,m,s,t;//k文化个数
int c[N],g[N][N],head[N],w[N*N],to[N*N],next[N*N],cnt=0,dis[N];
void add(int u,int v,int ww){next[++cnt]=head[u];to[cnt]=v;w[cnt]=ww;head[u]=cnt;}
struct node
{
    int from,is[N];
};
queue <node > q;
void spfa()
{
    node mes;
    for(int i=1;i<=k;i++)
        mes.is[i]=g[c[s]][i];
    mes.from=s;
    mes.is[c[s]]=0;
    q.push(mes);
    memset(dis,0x3f,sizeof(dis));
    dis[s]=0;
    while(!q.empty())
    {
        node tt=q.front();
        q.pop();
        for(int i=head[tt.from];i;i=next[i])
        {
            int v=to[i];
            if(tt.is[c[v]]&&dis[tt.from]+w[i]<dis[v])
            {
                node tmp=tt;
                dis[v]=dis[tt.from]+w[i];
                for(int j=1;j<=k;j++)
                    if(!g[c[v]][j])
                        tmp.is[j]=0;
                tmp.is[c[v]]=0;
                tmp.from=v;
                q.push(tmp);
            }
        }
    }
    if(dis[t]==0x3f3f3f3f) printf("-1\n");
    else printf("%d\n",dis[t]);
}
int main()
{
    scanf("%d%d%d%d%d",&n,&k,&m,&s,&t);
    for(int i=1;i<=n;i++) scanf("%d",c+i);
    for(int i=1;i<=k;i++)
        for(int j=1;j<=k;j++)
        {
            scanf("%d",&g[j][i]);
            g[j][i]^=1;
        }
    int u,v,ww;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&u,&v,&ww);
        add(u,v,ww),add(v,u,ww);
    }
    spfa();
    return 0;
}

2018.6.17

猜你喜欢

转载自www.cnblogs.com/ppprseter/p/9193694.html
今日推荐