丧的时候多给自己打气哇!

做图论就是好慢啊……比做出来更难的就是,找不到自己错在哪里了……

贴个题干!

 

简言之,就是你是一个消防队,你在A,B失火了,让你选择最短的路径,并统计这样的路有几条,并通知途径城市的消防队加入救援,最短路径中能号召的最多队伍是多少。

听起来不难吧……

上学期的我看到这道题要哭了,完全没有思路,现在懂了一些图论的知识,所以有了一点想法。

我用的是弗洛伊德算法,就是任选两点,不断往里面加节点(也就是加拐弯的地方),尝试寻找更短的路径,也就是说要n*n*n层循环,找出任意两点间的最短距离。

核心代码为:

for (k = 0; k <= citynum; k++)
	{
		for (i = 0; i <= citynum; i++)
		{
			for (j = 0; j <= citynum; j++)
			{
				if (k == i || k == j || i == j)
					continue;
				if (road[i][k]<INF&&road[k][j]<INF&&road[i][j] == road[i][k] + road[k][j])//同等长度路径数目增加
				{
					num[i][j]++;//寻找i j 两个节点间最小距离
					rt[i][j] = max(rt[i][j], rt[i][k] + rt[k][j]-resnum[k]);//记录最大救援队数量
				}
				else if (road[i][k]<INF&&road[k][j]<INF&&road[i][j]>road[i][k] + road[k][j])//同等长度的路径
				{
					road[i][j] = road[i][k] + road[k][j];
					rt[i][j] = max(rt[i][j], rt[i][k] + rt[k][j]-resnum[k]);
					num[i][j] = 1;//新的最短路径
				}
			}
		}
	}

为了完成题目,统计了等长条件下的路径长度,原版只要找出小于的情况即可。

同时要记录最短路径条件下,最多救援队的数目。

rt[i][j] = max(rt[i][j], rt[i][k] + rt[k][j]-resnum[k]);//记录最大救援队数量

 二者取最大,同时记得减去过度节点k本身的救援队数目,不然结果就是i  k k j三处救援队数目的总合……

然后考虑两种特殊情况,一个是救援地就是所在地,路径为1 救援队数目就是所在地的救援队数目;第二种就是二者有直达路线,这种情况,仍需考虑有更短的捷径出现的可能。

然鹅,这道题还是只有13/25,不知道错在哪里了……这个很蛋疼……

#include<iostream>
#include<stack>
#include<algorithm>
#include<string.h>
using namespace std;
#define INF 999999

int main()
{
	//cout << INF << "uuuuuuuuu" << endl;
	int citynum, roadnum, home, sos;
	cin >> citynum >> roadnum;
	cin >> home >> sos;//城市数目,道路数目,出发点,目的地
	int resnum[500] ;
	memset(resnum, 0, sizeof(resnum));//矩阵初始化
	int i = 0, res;

	while (i<citynum)
	{
		cin >> res;
		resnum[i] = res;
		i++;
	}

	int go, to, l;
	static int road[500][500] ;//初始化两点距离
	memset(road, INF, sizeof(road));
	static int num[500][500] ;//每两个节点间最短路径的数量;
	memset(num, 0, sizeof(num));
	static int rt[500][500];//每两个节点间的救援队数量;
	memset(rt, 0, sizeof(rt));
	//cout << rt[1][2] << "ssssssss" << endl;
	i = 0;

	while (i<roadnum)
	{
		cin >> go >> to >> l;
		road[go][to] = l;//录入两点间距
		road[to][go] = l;
		num[go][to] = 1;//两个节点间最短路径条数初始化
		num[to][go] = 1;
		rt[go][to] = resnum[go] + resnum[to];//两个节点间救援队数目初始化
		rt[to][go] = rt[go][to];
		i++;
	}
	if (home == sos)//如果起始位置一致
	{
		cout << "1 " << resnum[home];
		system("PAUSE");
		return 0;
	}

	int j, k;
	int lol = INF; int team = 0;//初始化
	int count = 0;

	for (i = 0; i < citynum; i++)
	{
		road[i][i] = 0;
		rt[i][i] = resnum[i];
	}

	if (road[home][sos] < INF)//如果存在直达
	{
		team=1;//初始化
		lol = road[home][sos];
		count = rt[home][sos];
	}

	for (k = 0; k <= citynum; k++)
	{
		for (i = 0; i <= citynum; i++)
		{
			for (j = 0; j <= citynum; j++)
			{
				if (k == i || k == j || i == j)
					continue;
				if (road[i][k]<INF&&road[k][j]<INF&&road[i][j] == road[i][k] + road[k][j])//寻找i j 两个节点间最小距离
				{
					num[i][j]++;//同等长度路径数目增加
					rt[i][j] = max(rt[i][j], rt[i][k] + rt[k][j]-resnum[k]);//记录最大救援队数量
				}
				else if (road[i][k]<INF&&road[k][j]<INF&&road[i][j]>road[i][k] + road[k][j])//同等长度的路径
				{
					road[i][j] = road[i][k] + road[k][j];
					rt[i][j] = max(rt[i][j], rt[i][k] + rt[k][j]-resnum[k]);
					num[i][j] = 1;//新的最短路径
				}
			}
		}
	}

	for (i = 0; i < citynum; i++)
	{
		for (j = 0; j < citynum; j++)
		{
			cout << road[i][j] << "  ";
		}
		cout << endl;
	}
	cout << "*******************************************************" << endl;


    cout<<num[home][sos]<<" "<<rt[home][sos];
	system("PAUSE");
	return 0;
}

然后昨晚和鸭子讨论了半天,为什么定义了500*500的矩阵就超出范围了???

然后发现是不能定义在main函数内,写在外面或者申请静态储存即可,static……

还有一点就是矩阵初始化,天真的我以为={0}就可以全部为0了,不知道谁给我的勇气Hhhhhhhh,正确示范,

memset(resnum, 0, sizeof(resnum));

 resnum位置是数组名,中间值是初始值……

需要头文件<string.h>

大概就这些知识点吧……


华丽丽的分割线,又换了个解法,使用的是迪杰斯特拉算法,空间复杂度更小一点,来不及了,不是解释了。反正错的还是一样的测试点,(毕竟我的解题思路一样哈哈哈哈哈哈哈

贴个代码,依旧是13/25

/***对于无向图,输入n,m,点的编号是1~n,然后是m行,每行4个数 a,b,d,p,表示a和b之间有一条边,且其长度为d,花费为p。最后一行是两个数s,t;起点s,终点 t。***/
/***n和m为 0 时输入结束。(1<n<=1000, 0<m<100000, s != t)     输出:输出一行,有两个数, 最短距离及其花费。***/
#include <iostream>
#include <iomanip>
#include <algorithm>
#include<string.h>
using namespace std;
#define nmax 500
#define inf 99999999

struct Edge
{
	int len;
	int cost;
};

Edge edge[nmax][nmax];
int dst[nmax], spend[nmax], book[nmax], n, m, stNode, enNode,time1[nmax];

int main()
{
	cin >> n >> m >> stNode >> enNode;
	int a, b, i, j;
	//构建邻接矩阵和最短路径数组
	for (i = 0; i < n; i++)//初始化
		{
			for (j = 0; j < n; j++)
			{
				edge[i][j].cost = 0;
				edge[i][j].len = inf;
			}
			time1[i] = 0;//道路数置0
			edge[i][i].len = 0;//对角线元素
			cin >> edge[i][i].cost;//对角线元素为各个城市的消防队数目
		}
		
		while (m--)
		{	
			cin >> a >> b;//输入道路起始点
			cin >> edge[a][b].len ;
			edge[b][a].len = edge[a][b].len;//道路长度
			edge[b][a].cost = edge[a][a].cost+edge[b][b].cost;//途径的消防队数量
			edge[a][b].cost = edge[b][a].cost;
		}

		/*for (i = 0; i < n; i++)
		{
			for (j = 0; j < n; j++)
			{
				cout << edge[i][j].len << "  ";
			}
			cout << endl;
		}*/
		if(stNode==enNode)
        {
            cout<<"1 "<<edge[stNode][stNode].cost;
            return 0;
        }
		for (i = 0; i < n; i++)
		{
			dst[i] = edge[stNode][i].len;
			spend[i] = edge[stNode][i].cost;
			//cout << dst[i] << " " << spend[i] << endl;
		}
		memset(book, 0, sizeof(book));
		book[stNode] = 1;

		//开始迪杰斯特拉算法,进行剩余n-1次松弛
		int k;
		for (k = 0; k < n ; k++)
		{
			//找离源点最近的顶点u
			int minNode=0, min = inf;
			for (i = 0; i < n; i++)
			{
				if (book[i] == 0 && min > dst[i] /* || min == dst[i]&& edge[stNode][min].cost > edge[stNode][i].cost*/)
				{
					min = dst[i];
					minNode = i;
					//cout << minNode <<endl;
				}
			}
			//cout << setw(2) << minNode;
			book[minNode] = 1;
			//以中心点u为转折点来更新路径数组和花费数组
			for (i = 0; i < n; i++)
			{
				if (i == minNode)
					continue;
				if (dst[i] == dst[minNode] + edge[minNode][i].len )
				{
					//同等更短路径
					time1[i] ++;
					//cout << "Q:" << i << " " << time1[i] << endl;
					spend[i] = max(spend[i], edge[minNode][i].cost + edge[stNode][minNode].cost - edge[minNode][minNode].cost);
				}
				else if (book[i] == 0 && dst[i] > dst[minNode] + edge[minNode][i].len)//新的更短路径
				{
					dst[i] = dst[minNode] + edge[minNode][i].len;
					spend[i] = max(spend[i], edge[minNode][i].cost + edge[stNode][minNode].cost - edge[minNode][minNode].cost);
					time1[i] = 1;
				}
			}
		}
		cout << time1[enNode]<<" "<< spend[enNode] ;
		system("PAUSE");
		return 0;
}

对了答案还是不知道哪里错了哈哈哈哈假期问问老宋!

发布了42 篇原创文章 · 获赞 16 · 访问量 2885

猜你喜欢

转载自blog.csdn.net/weixin_44412218/article/details/101697300