(题目描述略)
对于这道题,最好的方法是直接BFS,而大多数通过动归解决的算法都不太可能是完全正确的。
代码如下:
#include"stdio.h"
#include"string.h"
struct construction
{
bool tc[105],td[105];//tc记录文化是否学习,td记录国家是否到达
int now,sum;//now记录当前节点,sum记录当前路径长度
}q[50000];//模拟队列
int a[105][105],c[105],k,map[105][105],reflect[50000];
bool judge(int i,int j)
{
for(int l=1;l<=k;l++)
if(q[i].tc[l]&&a[c[j]][l]==1)
return false;
return true;
}
int main()
{
freopen("culture.in","r",stdin);
freopen("culture.out","w",stdout);
memset(map,-1,sizeof(map));
int ans=-1,m,n,s,t,top=1,u,v;
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",&a[i][j]);
a[i][i]=1;
}
while(m--)
{
scanf("%d %d",&u,&v);
scanf("%d",&map[u][v]);
if(map[v][u]==-1||map[u][v]<map[v][u])
map[v][u]=map[u][v];
}
reflect[0]=q[0].sum=0;
q[0].now=s;
q[0].tc[c[s]]=q[0].td[s]=true;
for(int i=0;i<top;i++)
{
if(top>20000)
{
printf("-1");
return 0;
}
if(q[reflect[i]].now==t)
{
ans=q[reflect[i]].sum;
break;
}
for(int j=1;j<=n;j++)
if(map[q[reflect[i]].now][j]!=-1&&!q[reflect[i]].td[j]&&judge(reflect[i],j))
{
q[top].now=j;
q[top].sum=q[reflect[i]].sum+map[q[reflect[i]].now][j];
for(int l=1;l<=k;l++)
q[top].tc[l]=q[reflect[i]].tc[l];
for(int l=1;l<=n;l++)
q[top].td[l]=q[reflect[i]].td[l];
q[top].tc[c[j]]=true;
q[top].td[j]=true;
reflect[top]=top++;//reflect调整节点搜索次序,使路径最短
for(int l=top-2;i<l&&q[reflect[l]].sum>q[reflect[l+1]].sum;l--)
m=reflect[l],reflect[l]=reflect[l+1],reflect[l+1]=m;
}
}
printf("%d",ans);
return 0;
}
由于本题官方数据过弱,导致某些没有考虑文化相斥的算法也能通过。当然,由于笔者也因无正确数据而无法保证此程序对于考虑文化相斥数据的正确性。不过,此算法的思路是基于考虑文化相斥的,虽然时间较动归算法而言略慢,但仍不失为一种考虑周全的算法。