P1078 [NOIP2012 普及组] 文化之旅

https://www.luogu.com.cn/problem/P1078
搜索,图论,剪枝,最短路
绿色题
思路一:搜索
1.输入,建边,用一个数组存储已经学习的文化,
2.搜索,以当前的点now去看能走到哪些边,然后对连上的点判断是否学过要去的点的文化,或要去的点排斥自己已经学过的文化的任意一种
3.剪枝方法一: 如果当前长度>=ans ,就直接return (这样还是会TLE掉一个点(92分))

 

 

4.剪枝方法二: 可以直接开一个数组存储从起点到图任意一点的最短路程,如果当前路程大于到当前点的最短路程就直接return (这样做可以拿满分)

 

 

#include<bits/stdc++.h>
using namespace std;
const int maxn=105;
int n,k,m,s,t,c[maxn],a[maxn][maxn],tot,cnt,whk[maxn],ans=1e9,p[maxn][maxn],flag2=0,ssum[maxn];
bool flag;
/*struct edge{
	int dis,to,next;
}e[maxn];
void add(int u,int v,int w)
{
	tot++;
	e[tot].next=head[u];
	e[tot].to=v;
	head[u]=tot;
}*/
void dfs(int now,int sum)
{   
    if(sum>=ssum[now])
    {
    	return;
	}
	ssum[now]=sum;
	if(now==t)
	{
		flag2=1;
		return;
	}
	
	for(int i=1; i<=n; i++)
	{
		if(p[now][i]>0)
		{
			flag=1;
			for(int j=1; j<=cnt; j++)
			{
				if(a[c[i]][whk[j]]==1) 
				{
					flag=0;
					break;
				}
			}
			if(flag==1)
			{
				whk[++cnt]=c[i];
				dfs(i,sum+p[now][i]);
				cnt--;
			}
		}
	}
		return;
}
int main()
{
	cin>>n>>k>>m>>s>>t;
	for(int i=1; i<=n; i++) ssum[i]=1e9;
	for(int i=1; i<=n; i++)
	{
		cin>>c[i];
	}
	for(int i=1; i<=k; i++)
	{
		for(int j=1; j<=k; j++)
		{
			cin>>a[i][j];
		}
		a[i][i]=1;
	}
	for(int i=1; i<=m; i++)
	{
			int u,v,d;
			cin>>u>>v>>d;
			if(p[u][v]==0||d<p[u][v]) p[u][v]=d;
			p[v][u]=d;
	}
	cnt=1; whk[cnt]=c[s];
	dfs(s,0);
	if(flag2==1)
	cout<<ssum[t]<<endl;
	else{
		cout<<-1<<endl;
	}
	return 0;
}

  

 
posted @ 2022-09-22 22:43  -イレイナ  阅读(171)  评论(0)    收藏  举报