srm 626 T2

题目大意:给定一张有向图,每条边有一个权值,问从1号点到达n号点的最小花费是多少。现在可以使用最多M次魔法,每次可以把当前路过的边的代价cost变成-cost(经过后代价就会变回去,对每条边可使用任意次魔法)。


主要思路:这题的做法是矩阵乘法。我们先用floyed预处理出每对点之间不使用魔法的最短距离还有最多使用一次魔法的最短距离,用邻接矩阵分别存为a、i。我们定义 C =  A * B 为 Cij = min{ Aik + Bkj },显然 {a^M}[1][n] 就是答案(其中 i 为单位矩阵)。可以证明 这种乘法是满足结合率的,所以我们可以利用矩阵乘法快速求出 a^M。


#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;

typedef long long LL;
const int N = 55;
LL g[N][N];

struct Matrix {
    LL a[N][N];
    int n;
    Matrix() { memset(a, 63, sizeof(a)); }
    
    Matrix operator * (const Matrix &b) const {
	Matrix c;
	c.n = n;
	for (int i = 1; i <= n; ++i)
	    for (int j = 1; j <= n; ++j)
		for (int k = 1; k <= n; ++k)
		    c.a[i][j] = min(c.a[i][j], a[i][k] + b.a[k][j]);
	return c;
    }
};

Matrix aa, I;

Matrix find(int t) {
    Matrix ans = I, z = aa;
    for (; t; t >>= 1, z = z * z) 
	if (t & 1) ans = ans * z;
    return ans;
}

class NegativeGraphDiv1 {
public:
    LL findMin(int n, vector <int> from, vector <int> to, vector <int> weight, int charges) {
	int m = from.size();
	memset(g, 63, sizeof(g));
	for (int i = 0; i < m; ++i) {
	    int x = from[i], y = to[i], z = weight[i];
	    g[x][y] = min(g[x][y], (LL)z);
	}
	for (int i = 1; i <= n; ++i)
		g[i][i] = 0;
	for (int k = 1; k <= n; ++k)
	    for (int i = 1; i <= n; ++i)
		for (int j = 1; j <= n; ++j)
		    g[i][j] = min(g[i][j], g[i][k] + g[k][j]);
	aa.n = I.n = n;
	for (int i = 1; i <= n; ++i)
	    for (int j = 1; j <= n; ++j)
		I.a[i][j] = aa.a[i][j] = g[i][j];
	for (int i = 1; i <= n; ++i)
	    for (int j = 1; j <= n; ++j) 
		for (int k = 0; k < m; ++k) {
		    int x = from[k], y = to[k], z = weight[k];
		    aa.a[i][j] = min(aa.a[i][j], g[i][x] + g[y][j] - z);
		    
		}
	Matrix ans = find(charges);
	return ans.a[1][n];
    }
};


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值