Silver Cow Party (转置 + 最短路)

One cow from each of N farms (1 ≤ N ≤ 1000) conveniently numbered 1..N is going to attend the big cow party to be held at farm #X (1 ≤ X ≤ N). A total of M (1 ≤ M≤ 100,000) unidirectional (one-way roads connects pairs of farms; road i requiresTi (1 ≤ Ti ≤ 100) units of time to traverse.

Each cow must walk to the party and, when the party is over, return to her farm. Each cow is lazy and thus picks an optimal route with the shortest time. A cow's return route might be different from her original route to the party since roads are one-way.

Of all the cows, what is the longest amount of time a cow must spend walking to the party and back?

Input

Line 1: Three space-separated integers, respectively: NM, and X 
Lines 2.. M+1: Line i+1 describes road i with three space-separated integers: Ai,Bi, and Ti. The described road runs from farm Ai to farm Bi, requiring Ti time units to traverse.

Output

Line 1: One integer: the maximum of time any one cow must walk.

Sample Input

4 8 2
1 2 4
1 3 2
1 4 7
2 1 1
2 3 5
3 1 2
3 4 4
4 2 3

Sample Output

10

Hint

Cow 4 proceeds directly to the party (3 units) and returns via farms 1 and 3 (7 units), for a total of 10 time units.

 

题意:

    给N个牧场,每个牧场里有一头牛,他们都要到第X个牛的牧场里聚会,然后返回各自的牧场,给定M组数据,代表从x到y牧场所用的时间(有向),问来回时间最长的牛所花费的时间,都是走最短路径;

思路:

    刚开始暴力了一波,求了n次的最短路,结果超时了(QAQ理所当然!),问了下 dalao 才知道先求从x到各个农场的最短路dir【】,然后将有向图map【】【】的对称值交换一下,即map【i】【j】=map【j】【i】;因为是有向图,原本从各牧场x的路径是dis【i】【x】,原本是从1到2有路,求从1(i)到2(x)的路径,现在换成从2到1有路,求从2(x)到1(i)的路径,仔细想想是不是一样的呢?(重要!!!)所以交换后,再从x处出发,到达各牧场的路径和从 原本各牧场出发到x的路径是一样的;即求得dis【x】【i】,在遍历n个点,求dir+dis的最大值!

图示:

这是一个有向图,正常暴力的话是求从各顶点到2号顶点的距离(红色),然后调换后(蓝色)(还是原本的有向图,不过是将以前起点,终点互换),路还是以前的路,只是起点和终点换了一下而已。

代码如下:

#include<cstdio>
#include<cstring>
#define inf 0x3f3f3f3f
int map[1010][1010],dis[1010],dir[1010],book[1010];
int main()
{
	int n,m,t,i,j,k,p;
	while(~scanf("%d%d%d",&n,&m,&t))
		{
			for(i=1; i<=n; i++)     //初始化
				for(j=1; j<=n; j++)
					if(i==j)map[i][j]=0;
					else map[i][j]=map[j][i]=inf;
			for(i=1; i<=m; i++)  //有向图输入
				{
					int a,b,c;
					scanf("%d%d%d",&a,&b,&c);
					if(map[a][b]>c)
						map[a][b]=c;
				}
            //求t到个牧场的最短路 dir【】
			for(i=1; i<=n; i++)
				dir[i]=map[t][i];
			memset(book,0,sizeof(book));
			book[t]=1;
			for(i=1; i<=n; i++)
				{
					int minn=inf;
					for(j=1; j<=n; j++)
						{
							if(!book[j]&&dir[j]<minn)
								{
									k=j;
									minn=dir[j];
								}
						}
					if(minn==inf)break;
					book[k]=1;
					for(j=1; j<=n; j++)
						{
							if(!book[j]&&dir[j]>minn+map[k][j])
								{
									dir[j]=minn+map[k][j];
								}

						}
				}

			for(i=1; i<=n; i++)   //交换地图的对称值,map[i][j]=map[j][i]
				for(j=i+1; j<=n; j++)
					{
						int tt=map[i][j];
						map[i][j]=map[j][i];
						map[j][i]=tt;
					}

			for(i=1; i<=n; i++)  //重新求t到各牧场的最短距离,即去聚会时各牛用的时间
				dis[i]=map[t][i];
			memset(book,0,sizeof(book));
			book[t]=1;
			for(i=1; i<=n; i++)
				{
					int minn=inf;
					for(j=1; j<=n; j++)
						{
							if(!book[j]&&dis[j]<minn)
								{
									k=j;
									minn=dis[j];
								}
						}
					if(minn==inf)break;
					book[k]=1;
					for(j=1; j<=n; j++)
						{
							if(!book[j]&&dis[j]>minn+map[k][j])
								dis[j]=minn+map[k][j];
						}
				}
				
			int maxx=-1;
			for(i=1; i<=n; i++)  //打擂台法,求 来(dis)回(dir)的和最大的值
				if(dis[i]+dir[i]>maxx)
					maxx=dis[i]+dir[i];
			printf("%d\n",maxx);
		}
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
假设a和v都是n行1列的向量,可以将av和va专表示为矩阵相乘的形式,即av为n×n矩阵A和n×1列向量v的乘积,va专为n×1列向量v和1×n矩阵A专的乘积。则原方程可以表示为矩阵方程: A*v + (A')*v + n = 0 移项得: (A + A')*v = -n 因为n是符号矩阵,即只有0和1两个元素,因此可以将其表示为2n-1的形式,其中2表示2倍,n-1表示矩阵中的元素只能是-1或1。于是原方程可以进一步表示为: (A + A')*v = -(2n-1) 因为A和A'都是实对称矩阵,因此A+A'也是实对称矩阵,可以使用eig函数求解其特征值和特征向量。特征值为正的特征向量构成的矩阵就是(A+A')的正交基,可以用它来求解v的解析表达式。具体地,假设(A+A')的特征值为λ1, λ2, ..., λn,对应的特征向量为v1, v2, ..., vn,则有: v = c1*v1 + c2*v2 + ... + cn*vn 其中c1, c2, ..., cn为待确定的常数。将v代入原方程,有: (A + A')*(c1*v1 + c2*v2 + ... + cn*vn) = -(2n-1) 左右两边同时乘以vi的,得: λi*vi'*(c1*v1 + c2*v2 + ... + cn*vn) = -vi'*(2n-1) 因为(A+A')的特征向量是正交的,即vi'vj=0 (i≠j),因此上式可以进一步化简为: λi*ci = -vi'*(2n-1) 则有: ci = -vi'*(2n-1) / λi 将ci代入v的表达式即可得到v的解析表达式。具体实现代码如下: % 输入矩阵a和符号矩阵n a = [1; 2; 3]; n = eye(3); % 计算(A+A')的特征值和特征向量 A = a*a' + (a*a)'; [V, D] = eig(A); lambda = diag(D); % 计算常数c c = -V'*(2*n-1) ./ lambda; % 计算v的解析表达式 v = V*c; % 输出结果 disp(v);

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值