今天考了一道分层图,本来是一道板题,结果我被误导了,想成了 架设电话线一题,考完写炸了才发现,架设电话线只需要求出第k+1大的长度,只需要满足局部最优,但是飞行线路要使总和最小,只能用分层图,然后我翻了半天标签,找到了这道题。
 
link
 
但是当旁边LH看到之后,他告诉我,这是一道DP。
 
结果我没看出来。。。
 
分层图倒是很简单。
 
Sulotion
 
step1 首先,他可以在图上到处走动,所以很自然地可以建一张图,所有的边权都是0。 然后这道题只与水晶球的价格有关,所以我们把点权搬到边权上面。 step2 因为他只进行一次买卖,所以有下面两种情况: 假设从
    
     
      
       
        u
       
      
      
       u
      
     
    u到
    
     
      
       
        v
       
      
      
       v
      
     
    v,水晶球在
    
     
      
       
        u
       
      
      
       u
      
     
    u的价格为
    
     
      
       
        w
       
      
      
       w
      
     
    w. 1.买. 建第二层图,连接第一层图 -> 在
    
     
      
       
        u
       
      
      
       u
      
     
    u和
    
     
      
       
        v
       
      
      
       v
      
     
    v之间建一条边边权为
    
     
      
       
        −
       
       
        w
       
      
      
       -w
      
     
    −w。 2.卖. 建第三层图,连接第二层图 -> 在
    
     
      
       
        u
       
      
      
       u
      
     
    u和
    
     
      
       
        v
       
      
      
       v
      
     
    v之间建一条边边权为
    
     
      
       
        w
       
      
      
       w
      
     
    w。 step3 我们在最后有两种方法走向终点: 不买卖直接走向终点 直接在第一层图的n号节点建立边权为0的有向边接入一个“大终点” 买卖一次后走向终点 在第三层图的n号节点建立边权为0的有向边接入“大终点”
 
至此,这道题就只需要求一个最长路即可。
 
Code
 
#include <queue>
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std
;
const int MAXN 
= 100005 * 3 + 1;
int n
, m
, a
[MAXN
];
bool vis
[MAXN
];
int dis
[MAXN
];
queue
<int> q
;
void read(int& x
) {
	x 
= 0;
	int f 
= 1;
	char c 
= getchar();
	while (c 
> '9' || c 
< '0') {
		if (c 
== '-') f 
= -f
;
		c 
= getchar();
	}
	while (c 
<= '9' && c 
>= '0') {
		x 
= x 
* 10 + c 
- '0';
		c 
= getchar();
	}
	x 
*= f
;
}
struct edge 
{
	int v
, w
;
	edge(){}
	edge(int V
, int W
) {
		v 
= V
;
		w 
= W
;
	}
};
vector
<edge
> G
[MAXN
];
void AddEdge(int u
, int v
, int w
) {
	G
[u 
+ n 
* 0].push_back(edge(v 
+ n 
* 0, 0));
	G
[u 
+ n 
* 1].push_back(edge(v 
+ n 
* 1, 0));
	G
[u 
+ n 
* 2].push_back(edge(v 
+ n 
* 2, 0));
	G
[u 
+ n 
* 0].push_back(edge(v 
+ n 
* 1, -w
));
	G
[u 
+ n 
* 1].push_back(edge(v 
+ n 
* 2, w
));
}
void Spfa() {
	memset(vis
, 0, sizeof(vis
));
	memset(dis
, 0xcf, sizeof(dis
));
	dis
[1] = 0;
	vis
[1] = 1;
	q
.push(1);
	while (q
.size()) {
		int u 
= q
.front();
		q
.pop();
		vis
[u
] = 0;
		for (int i 
= 0; i 
< G
[u
].size(); i
++) {
			int v 
= G
[u
][i
].v
, w 
= G
[u
][i
].w
;
			if (dis
[v
] < dis
[u
] + w
) {
				dis
[v
] = dis
[u
] + w
;
				if (vis
[v
] == 0) {
					vis
[v
] = 1;
					q
.push(v
);
				}
			}
		}
	}
	printf 
("%d\n", dis
[n
]);
}
int main() {
	read(n
);
	read(m
);
	for (int i 
= 1; i 
<= n
; i
++) {
		read(a
[i
]);
	}
	for (int i 
= 1, u
, v
, opt
; i 
<= m
; i
++) {
		read(u
), read(v
), read(opt
);
		AddEdge(u
, v
, a
[u
]);
		if (opt 
== 2) {
			AddEdge(v
, u
, a
[v
]);
		}
	}
	G
[n
].push_back(edge(n 
* 3 + 1, 0));
	G
[n 
* 3].push_back(edge(n 
* 3 + 1, 0));
	n 
*= 3;
	n
++;
	Spfa();
	return 0;
}