M - Walking Plan HDU - 6331

分块+floyd
令dp[i][j][k]表示i到j恰好k条路经的最小权值。那么就有:dp[i][j][k]=min{dp[i][p][k-1]+dp[p][j][1]}我们可以预处理出前100条路径的dp值。然后考虑大范围转移,对dp[i][j][100]做一次floyd转移到200,再做一次转移到300,以此类推。
就可以求得,从j到j恰好k条路径的最小权值。
题目要求至少k条路径。那么对于小范围1~100的dp,我们从大往小,取min值,便可以表示从i到j至少k条路经的最小权值。对于大范围,dp[i][j][k*100],因为1~100的值我们已经更新过了,所以使用1~100来更新每一个k*100,便可以表示,至少k*100条路经,但少于(k+1)*100条路径的最小权值。查询的时候优先查询100的倍数,剩下的值通过1~100补全。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<bitset>
#include<map>
//#include<regex>
#include<cstdio>
#pragma GCC optimize(2)
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
typedef unsigned long long ull;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
ll read()
{
	char ch = getchar(); ll x = 0, f = 1;
	while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
	return x * f;
}
typedef pair<int, int> pir;
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lrt root<<1
#define rrt root<<1|1
int T;
int n, m, q;
const int mod = 1e9 + 7;
struct mat {
	int a[55][55];
	int n;
	void init(int n)
	{
		this->n = n;
		upd(i, 0, n)upd(j, 0, n)a[i][j] = mod;
	}
}dp_sm[105], dp_big[105];
mat floyd(mat dp1, mat dp2, mat dp3)
{
	mat res; res.init(n);
	int len = dp1.n;
	upd(i, 1, len)upd(j, 1, len)res.a[i][j] = min(res.a[i][j], dp3.a[i][j]);
	upd(k, 1, len)
	{
		upd(i, 1, len)
		{
			upd(j, 1, len)
			{
				if (dp1.a[i][k] == mod || dp2.a[k][j] == mod)continue;
				res.a[i][j] = min(res.a[i][j], dp1.a[i][k] + dp2.a[k][j]);
			}
		}
	}
	return res;
}
int main()
{
	T = read();
	while (T--)
	{
		n = read(), m = read();
		int u, v; int w;
		upd(i, 0, 100)dp_sm[i].init(n), dp_big[i].init(n);
		upd(i, 0, n)dp_sm[0].a[i][i] = dp_big[0].a[i][i] = 0;
		upd(i, 1, m)
		{
			u = read(), v = read(), w = read();
			dp_sm[1].a[u][v] = min(dp_sm[1].a[u][v], w);
		}
		upd(i, 0, 100)
		{
			dp_sm[i + 1] = floyd(dp_sm[1], dp_sm[i], dp_sm[i + 1]);
		}
		//upd(i, 1, n) { upd(j, 1, n) { printf("%d ", dp_sm[1].a[i][j]); }cout << endl; }
		dp_big[1] = dp_sm[100];
		upd(i, 0, 100)
		{
			dp_big[i + 1] = floyd(dp_big[1], dp_big[i], dp_big[i + 1]);
		}
		dwd(k, 99, 1)
		{
			upd(i, 1, n)upd(j, 1, n)dp_sm[k].a[i][j] = min(dp_sm[k + 1].a[i][j], dp_sm[k].a[i][j]);//反向取,表示至少
		}
		//upd(i, 1, n) { upd(j, 1, n) { printf("%lld ", dp_sm[1].a[i][j]); }cout << endl; }
		upd(i, 1, 100)
		{
			dp_big[i] = floyd(dp_big[i], dp_sm[1], dp_big[i]);
		}
		q = read();
		while (q--)
		{
			u = read(), v = read(), w = read();
			//cout << "*" << endl;
			int md = w % 100;
			int quan = w / 100;
			int ans = mod;
			//	upd(i, 1, n) { upd(j, 1, n) { printf("%lld ", dp_sm[1].a[i][j]); }cout << endl; }
			upd(k, 1, n)
			{
				//cout <<"k"<<k<<" "<< dp_sm[md].a[k][v] << endl;
				ans = min(ans, dp_big[quan].a[u][k] + dp_sm[md].a[k][v]);
			}
			if (ans == mod)printf("-1\n");
			else printf("%d\n", ans);
		}
	}
	return 0;
}
发布了208 篇原创文章 · 获赞 1 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_44019404/article/details/104953611