P6190 [NOI Online 入门组]魔法

P6190 [NOI Online 入门组]魔法

题目描述
分析

这道题要求的是从1到\(n\)的最短路,其中有\(k\)次机会可以将一条边暂时的变为相反数,一条边可以走无数次

注意到无数次这个比较奇怪的要求,也就是说可以不考虑重复,那么设\(a_{k,i,j}\)表示从\(i\)\(j\)\(k\)次魔法的最小值,那么显然\(a_{k,i,j}=min(a_{u,i,v}+a_{k-u,v,j})\),即把\(i\)\(j\)分为两段,那么首先对于\(k=0\)的情况,可以直接Floyd解决,对于\(k=1\)可以枚举所有的边解决,然后我们就得到了一个矩阵M,我们显然可以定义一种矩阵乘法\(a*b=min(a_{i,u}+b_{u,j})\)符合我们上面推出来的转移方程

那么对于\(k\)的情况,即用矩阵快速幂求出\(M^k\)即可

代码
#include<bits/stdc++.h>
using namespace std;

const int N=105;
struct Node
{
	long long matrix[N][N];
}a,b;
int n,m,k,edge[2505][3];

void Input()
{
	scanf("%d%d%d",&n,&m,&k);
	memset(a.matrix,63,sizeof(a.matrix));
	memset(b.matrix,63,sizeof(b.matrix));
	for(int i=1;i<=m;i++)
	{
		int x,y,z;
		scanf("%d%d%d",&x,&y,&z);
		a.matrix[x][y]=z;
		edge[i][0]=x; edge[i][1]=y; edge[i][2]=z;
	}
	return;
}

void Prepare()
{
	for(int i=1;i<=n;i++) a.matrix[i][i]=0;
	for(int kk=1;kk<=n;kk++)
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
//				if( i!=j && i!=kk && j!=kk )
					a.matrix[i][j]=min(a.matrix[i][j],a.matrix[i][kk]+a.matrix[kk][j]);
//	for(int i=1;i<=n;i++)
//	{
//		for(int j=1;j<=n;j++) cout<<a.matrix[i][j]<<" ";
//		cout<<endl;
//	}
	for(int i=1;i<=n;i++) b.matrix[i][i]=0;
	for(int kk=1;kk<=m;kk++)
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
				b.matrix[i][j]=min(b.matrix[i][j],min(a.matrix[i][j],a.matrix[i][edge[kk][0]]+a.matrix[edge[kk][1]][j]-edge[kk][2]));
//	for(int i=1;i<=n;i++)
//	{
//		for(int j=1;j<=n;j++) cout<<b.matrix[i][j]<<" ";
//		cout<<endl;
//	}
	return;
}

Node matrix_mul(Node A,Node B)
{
	Node tem;
	memset(tem.matrix,63,sizeof(tem.matrix));
	for(int kk=1;kk<=n;kk++)
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
				tem.matrix[i][j]=min(tem.matrix[i][j],A.matrix[i][kk]+B.matrix[kk][j]);
	return tem;
}

long long matrix_pow(Node x,int y)
{
	Node tem=a;
	while( y )
	{
		if( y%2 ) tem=matrix_mul(x,tem);
		x=matrix_mul(x,x);
		y/=2;
	}
	return tem.matrix[1][n];
}

void work()
{
	if( k==0 ) printf("%lld",a.matrix[1][n]);
	else printf("%lld",matrix_pow(b,k));
	return;
}

int main()
{
	Input();
	Prepare();
	work();
	return 0;
}
posted @ 2020-03-16 22:08  Boring__Zheng  阅读(155)  评论(0编辑  收藏  举报