FGD想从成都去上海旅游。由于FGD非常讨厌乘车的颠簸,他希望在满足他的要求的情况下,旅行的距离尽量短,这样他就有足够
的精力来欣赏风景。
整个城市交通网络包含N个城市以及城市与城市之间的双向道路M条。城市自1至N依次编号,道路亦然。没有从某个城市直接到它
自己的道路,两个城市之间最多只有一条道路直接相连,但可以有多条连接两个城市的路径。任意两条道路如果相遇,则相遇点也
必然是这N个城市之一,在中途,由于修建了立交桥和下穿隧道,道路是不会相交的。每条道路都有一个固定长度。在中途,FGD
想要经过K(K<=N-2)个城市。成都编号为1,上海编号为N,而FGD想要经过的N个城市编号依次为2,3,…,K+1. 举例来说,假设交通网
络如下图。FGD想要经过城市2,3,4,5,并且在2停留的时候在3之前,而在4,5停留的时候在3之后。那么最短的旅行方案是
1-2-4-3-4-5-8,总长度为19。注意FGD为了从城市2到城市4可以不路过城市3,但不在城市3停留。这样就不违反FGD的要求了。并且
由于FGD想要走最短的路径,因此这个方案正是FGD需要的。
第1行包含3个整数N(2< =N< =20000), M(1<=M<=200000),K(0< =K<=20)
第2..M+1行,每行包含3个整数X,Y,Z,(1 ≤ x < y ≤N, 1 ≤z ≤ 1000).表示城市x到城市y距离为z,数据保证必然存在一条路径从城市
1到城市n, 经过所有城市。
第M+2行,一个整数g, 0 ≤ g ≤k·(k−1)/2。表示FGD停留的限制条件有g个。
第M+3..M+2+g行,包含2个整数ri和si ,2 ≤ ri ≤ k +1, 2 ≤ si ≤ k +1, ri不等于si。FGD访问城市si之前,必须访问ri。
只包含一行,包含一个整数,表示最短的旅行距离
分析发现k个点的先后到达顺序影响答案,其他点无论何时访问对于答案的贡献是固定的。因此可以先把研究范围缩小到这k个点
中。鉴于k的大小比较友善,可以考虑状压这k个点的状态(已访问/未访问)。
先spfa预处理出这k个点到每个点的最短距离,设f[i][j]表示状态i下最后到达第j个点的最小最短路程,不难得出转移式:
f[s][i]=min(f[s'][j]+dis[i][j])
对于访问某些点之前必须先访问其他点的限制条件,不妨同样通过状压的方式存下访问点i之前必须访问的点,在在转移的时候跳过非法状态即可。
#include
#include
#include
using namespace std;
const int MAXN=20010;
const int MAXM=200010;
const int MAXK=22;
const int INF=1e9;
int n,m,k,g;
bool inq[MAXN];
int head[MAXN],tot,lim[MAXK],f[1<<20][MAXK],dis[MAXK][MAXN],ans=INF;
struct edge{int to,nxt,c;}e[MAXM<<1];
int getint(){
int v=0; char ch;
while(!isdigit(ch=getchar())); v=ch-48;
while(isdigit(ch=getchar())) v=v*10+ch-48; return v;
}
void insert(int u,int v,int cost){
e[++tot].to=v; e[tot].nxt=head[u]; head[u]=tot; e[tot].c=cost;
e[++tot].to=u; e[tot].nxt=head[v]; head[v]=tot; e[tot].c=cost;
}
void spfa(int S){
for(int i=1;i<=n;i++) dis[S][i]=INF; dis[S][S]=0;
queue Q; Q.push(S); inq[S]=true;
while(!Q.empty()){
int now=Q.front(); Q.pop();
for(int i=head[now];i;i=e[i].nxt){
if(dis[S][e[i].to]>dis[S][now]+e[i].c){
dis[S][e[i].to]=dis[S][now]+e[i].c;
if(!inq[e[i].to]){
Q.push(e[i].to);
inq[e[i].to]=true;
}
}
}
inq[now]=false;
}
}
int main(){
n=getint(); m=getint(); k=getint();
for(int i=1;i<=m;i++){
int a=getint(),b=getint(),c=getint();
insert(a,b,c);
}
g=getint();
for(int i=1;i<=g;i++){
int a=getint(),b=getint();
lim[b]|=(1<<(a-2));
}
for(int i=1;i<=k+1;i++) spfa(i);
for(int i=0;i<(1<