[刷题之旅no28]P2910 [USACO08OPEN]Clear And Present Danger S

1.给出结点数量,给出遍历结点数量
2.给出遍历结点顺序
3.给出结点之间的距离
4.求解一个路径,保证路径上面有2给出的结点顺序
OK
现在我们来求解这个问题
其实就是
1.读取结点数量
2.用一个数组储存遍历顺序
3.用一个二维数组储存当前两个结点之间的顺序
每个结点互相连通
最多100个结点(有点友好啊)
所以。我们只需要求解两点之间的最短路径即可。
用什么方法呢?
刚刚学了SPFA算法,感觉可以直接把这道题解决掉了。
外层循环,遍历所有结点
内层用我们的SPFA
1.初始化headl,tail
2.把起点入队
3.开始循环,
队首元素出队,找出和这个当前相连的所有点,然后比较长短
4.如果加和小于已经记录的值
5.那么直接更改,当前点入队,然后继续就可以了
大错特错的感觉真奇妙
看来我只空有SPFA的模板,而没学到人家的思路啊!!!
这道题的二维数组只用来记录数据,我咋在人家的基础之上进行删改呢?
spfa算法就是一个不断向着最短路径进行记录的过程,
问题:
1.队列开太短了,虽然每个题目只有100个结点,但是队列的head会根据bfs一直向后移
,所以一定要开得足够大
2.还是关于初始化的问题,我们需要常备着这个min数组,并且除了[i,i]其它都设置为最大值
不要动储存距离的数组
具体什么原理,我还要学
3.无了
放代码:

#include
int maze[105][105]={0},n,m,ord[10005]={0},line[100005]={0},tag[105]={0},head=1,tail=0,danger=0,min[105][105]={0};
const int inf=90000000;
int main()
{
	scanf("%d %d",&n,&m);
	for(int i=1;i<=m;i++)
	{
		scanf("%d",&ord[i]);
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			scanf("%d",&maze[i][j]);//从i到j 
		}
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			min[i][j]=inf;
		}
	}
	for(int i=1;i<=n;i++)
	{
		min[i][i]=0;
		head=1,tail=0;
		tail++;
		line[tail]=i;
		tag[i]=1;
		int start=i;
		while(1)
		{
			if(head>tail)
			{
				break;
			}
			int st=line[head];
			head++;
			tag[st]=0;
			for(int j=1;j<=n;j++)
			{
				if(min[start][j]>min[start][st]+maze[st][j])
				{
					min[start][j]=min[start][st]+maze[st][j];
					if(tag[j]==0)
					{
						tail++;
						line[tail]=j;
						tag[j]=1;
					}
				}
			}
		}
	}
//	for(int i=1;i<=n;i++)
//	{
//		for(int j=1;j<=n;j++)
//		{
//			printf("%d ",min[i][j]);
//		}
//		printf("\n");
//	}
	for(int i=2;i<=m;i++)
	{
		danger=danger+min[ord[i-1]][ord[i]];
	}
	printf("%d",danger);
	return 0;
}

你可能感兴趣的:([刷题之旅])