HDU-6705 path(2019CCPC网络赛1004) Kth路径 思维+套路题

HDU-6705 path(2019 CCPC网络赛1004)

You have a directed weighted graph with n vertexes and m edges. The value of a path is the sum of the weight of the edges you passed. Note that you can pass any edge any times and every time you pass it you will gain the weight.

Now there are q queries that you need to answer. Each of the queries is about the k-th minimum value of all the paths.

Input
The input consists of multiple test cases, starting with an integer t (1≤t≤100), denoting the number of the test cases.
The first line of each test case contains three positive integers n,m,q. (1≤n,m,q≤5∗104)

Each of the next m lines contains three integers ui,vi,wi, indicating that the i−th edge is from ui to vi and weighted wi.(1≤ui,vi≤n,1≤wi≤109)

Each of the next q lines contains one integer k as mentioned above.(1≤k≤5∗104)

It’s guaranteed that Σn ,Σm, Σq,Σmax(k)≤2.5∗105 and max(k) won’t exceed the number of paths in the graph.

Output
For each query, print one integer indicates the answer in line.

Sample Input
1
2 2 2
1 2 1
2 1 2
3
4

Sample Output
3
3
Hint

1->2 value :1

2->1 value: 2

1-> 2-> 1 value: 3

2-> 1-> 2 value: 3

Source
2019中国大学生程序设计竞赛(CCPC) - 网络选拔赛

题目大意:

给你一个n个点m条边的有向图
有k个询问,每个询问都有一个数qi 问 第 qi短的路径长度是多少。

解题思路:

猛地一看这个题很懵逼
因为路径长度有无数种,让你找第k小的

我们用优先队列来做
我们首先把每个点最小的出边放进优先队列里。
优先队列里的每个元素都有啥呢?
这表示了一条边,last就是出发的点,now就是到达的点,rank是last这个点的出边中这个边排第几小。dis就是现在路径长度时多少。

	int last;
	int now;
	int rank;
	ll dis;

HDU-6705 path(2019CCPC网络赛1004) Kth路径 思维+套路题_第1张图片
看这么一个图,红色代表的就是权值
那么我们最先放入优先队列里的是哪些边呢?(每个点最小的出边)
1点最小的出边就是 1->4这条边 那么这边放入优先队列中的元素 的 last =1 now = 2 rank = 0 dis = 1
2点没有出边,跳过
3点最小的出边是3->5这条边,那么这边放入优先队列中的元素 的 last =3 now =5 rank = 0 dis = 5
4最小的出边是4->2这条
3 6均没有出边。

然后我们把我们所有的查询离线一下,用一个数组que存起来,然后找一个最大的查询记作max_que
那么我们只需要处理前max_que小的路径长度即可
所以我们让优先队列弹max_que次,第i次都弹出的就是第i小的 用ans数组存一下然后输出。

存图:
我用 vector >G[maxn]来存图
因为,我们要对这个点所有的出边进行排序,如果用静态链表的话 好像没法实现。

AC代码:

#include 
#define ll long long
using namespace std;
const int maxn = 5e4+10;
struct node{
     
	int last;
	int now;
	int rank;
	ll dis;
	node(int last,int now,int rank,ll dis):last(last),now(now),rank(rank),dis(dis){
     }
	node(){
     }
	friend bool operator < (node a,node b){
     
		return a.dis>b.dis;
	}
};
vector<pair<int,ll> > G[maxn];//存图的
priority_queue<node> q; 
void add(int x,int y,ll w){
     
	G[x].push_back(make_pair(y,w));
}
bool cmp(pair<int,ll> a,pair<int,ll> b){
     
	return a.second<b.second;
}
int n,m,k;
int que[maxn];//记录询问
ll ans[maxn];
void init(){
     
	while(q.size()) q.pop();
	for(int i=1;i<=n;i++){
     
		G[i].clear();
	}
	memset(ans,0,sizeof(ans));
}
int main(){
     
	int t;
	cin>>t;
	while(t--){
     
		init();
		scanf("%d%d%d",&n,&m,&k);
		for(int i=1;i<=m;i++){
     
			int x,y;
			ll w;
			scanf("%d%d%lld",&x,&y,&w);
			add(x,y,w);
		}
		int max_que = 0;
		for(int i=1;i<=k;i++){
     
			scanf("%d",&que[i]);
			max_que = max(max_que,que[i]);
		}
		for(int i=1;i<=n;i++){
     
			sort(G[i].begin(),G[i].end(),cmp);
		}

		for(int i=1;i<=n;i++){
     
			if(G[i].size()){
     
				q.push(node(i,G[i][0].first,0,G[i][0].second));
			}
				
		}
		for(int i=1;i<=max_que;i++){
     
			node x = q.top();
			q.pop();
			ans[i] = x.dis;
			//cout<
			if(G[x.now].size()){
     
				q.push(node(x.now,G[x.now][0].first,0,x.dis+G[x.now][0].second));
			}
			if(x.rank+1<G[x.last].size()){
     
				q.push(node(x.last,G[x.last][x.rank+1].first,x.rank+1,x.dis-G[x.last][x.rank].second+G[x.last][x.rank+1].second));
			}
		}
		for(int i=1;i<=k;i++){
     
			printf("%lld\n",ans[que[i]]);
		}
	}
	return 0;
}

你可能感兴趣的:(图论,思维题,知识)