https://www.luogu.org/problem/show?pid=1078
直接搜就好,倒搜可以过最后一个点不超时
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define ms(i,j) memset(i,j,sizeof i);
int n;//国家总数
int k;//文化总数
int m;//道路总数
int s,t;//始终点
int ci[105];//每个国家的文化
int ki[105][105];//文化排斥情况邻接矩阵
int edge[105][105];//道路
bool wh[105];//搜索:是否学了第i种文化
int mini = 100000000;//搜索:当前最短路
bool vi[105];//搜索:是否访问过该节点
int dfs(int u, int cost)
{
wh[ci[u]] = true;//学习这种文化
vi[u] = true;
if (cost>=mini) {vi[u] = false;
wh[ci[u]] = false;return 0;}//剪枝
if (u==s)//到达终点
{
if (cost<mini) mini = cost;
vi[u] = false;
wh[ci[u]] = false;
return 0;
}
for (int i=1;i<=n;i++)//枚举所有连边
{
if (edge[u][i])
{
if (!vi[i])//没访问过那个节点
{
bool bj = false;
for (int j=1;j<=k;j++)//排斥
{
if (ki[ci[i]][j])
if (wh[j])
{
bj = true;
break;
}
if (ki[j][ci[i]])
if (wh[ci[i]])
{
bj = true;
break;
}
}
if (bj) continue;//有排斥,枚举下一个
dfs(i, cost+edge[u][i]);//继续搜索
}
}
}
wh[ci[u]] = false;
vi[u] = false;
}
int main()
{
//freopen("culture.in","r", stdin);freopen("culture.out","w", stdout);
scanf("%d%d%d%d%d", &n, &k, &m, &s, &t);
for (int i=1;i<=n;i++) scanf("%d", &ci[i]);
for (int i=1;i<=k;i++)
for (int j=1;j<=k;j++)
scanf("%d", &ki[i][j]);
ms(edge,127);
for (int i=1;i<=m;i++)
{
int u,v,d;
scanf("%d%d%d", &u, &v, &d);
if (edge[u][v]>d) edge[u][v] = d;
if (edge[v][u]>d) edge[v][u] = d;
}
ms(vi, false);
dfs(t,0);
if (mini==100000000) printf("-1\n"); else printf("%d\n", mini);
fclose(stdin); fclose(stdout);
return 0;
}