列表

详情


NC214409. 向死而生

描述

生者困于此地,死者方可离开

夜之城由n个节点组成,某些节点之间可能会有单向道路,这些道路有m条,我们称它们为旧路,由于2070年的公司战争,现增修了A条新路。每条旧路有一个权值c,代表通过这条道路所需要的体力,每条新路也有一个权值,不过是变化的。  
以第i条新路为例,一开始其权值为,若总共经过了j条新路,其权值就会变成(在完全通过一条新路才会变)。不会存在两条旧路连接相同的两个地标,也不会存在两条新路连接相同的两个地标。  
V位于1号点,现在V需要通过恰好k条旧路和B条新路(都可以重复经过),并最终停在任意位置。V希望知道完成这件任务最少需要消耗多少体力。

输入描述

输入第一行为五个正整数n,m,k,A,B  
接下来m行,每行三个整数x,y,c,表示从x到y有一条权值为c的旧路。  
接下来A行,每行前两个整数x,y,表示从x到y有一条新路,接下来B个整数,为

输出描述

输出仅一行,一个正整数,表示最小的体力。  
如果无法完成任务,请输出-1。

示例1

输入:

3 3 1 1 1
1 2 1
2 3 2
3 1 1
2 3 2

输出:

3

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++(clang++11) 解法, 执行用时: 443ms, 内存消耗: 2808K, 提交时间: 2021-04-03 19:49:41

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;

const int N=25;
struct mat{
	int r,c;
	ll a[225][225];
	mat(){
		r=c=0;
		memset(a,0x3f,sizeof(a));
	}
	mat operator * (const mat& T)const{
		mat res;
		res.r=r; res.c=T.c;
		for(int i=0;i<res.r;++i)
			for(int k=0;k<c;++k)
				for(int j=0;j<res.c;++j)
					res.a[i][j]=min(res.a[i][j],a[i][k]+T.a[k][j]);
		return res;
	}
};
mat fpw(mat x,ll k){
	assert(k);
	mat res=x;--k;
	while(k){
		if(k&1)res=res*x;
		x=x*x;k>>=1;
	}
	return res;
}
int n,m,A,B,g[N][N];
int getid(int x,int y){return x*(B+1)+y;}
ll k;
int main() {
	std::ios::sync_with_stdio (0);
	cin>>n>>m>>k>>A>>B;
	mat trans;
	trans.r=trans.c=n*(B+1);
	for(int i=0;i<m;++i){
		int x,y,c;
		cin>>x>>y>>c;
		--x,--y;
		for(int j=0;j<=B;++j) 
			trans.a[getid(x,j)][getid(y,j)]=min(trans.a[getid(x,j)][getid(y,j)],(ll)c);
	}
	for(int i=0;i<A;++i){
		int x,y;
		cin>>x>>y;
		--x,--y;
		for(int j=0;j<B;++j){
			int va;
			cin>>va;
			trans.a[getid(x,j)][getid(y,j+1)]=min(trans.a[getid(x,j)][getid(y,j+1)],(ll)va);
		}
	}
	mat st;
	st.r=1; st.c=n*(B+1);
	st.a[0][getid(0,0)]=0;
	mat res=st*fpw(trans,k+B);
	ll ans=0x3f3f3f3f3f3f3f3fll;
	for(int j=0;j<n;++j) ans=min(ans,res.a[0][getid(j,B)]);
	if(ans>1e18) cout<<-1<<'\n';
	else cout<<ans<<'\n';
	return 0;
}

上一题