题意:FGD想从成都去上海旅游。在旅途中他希望经过一些城市并在那里欣赏风景,品尝风味小吃或者做其他的有趣的事情。经过这些城市的顺序不是完全随意的,比如说FGD不希望在刚吃过一顿大餐之后立刻去下一个城市登山,而是希望去另外什么地方喝下午茶。幸运的是,FGD的旅程不是既定的,他可以在某些旅行方案之间进行选择。由于FGD非常讨厌乘车的颠簸,他希望在满足他的要求的情况下,旅行的距离尽量短,这样他就有足够的精力来欣赏风景或者是泡MM了^_^. 整个城市交通网络包含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需要的。
我们注意到K非常小,所以需要经过的城市可以状压起来,预处理出每对必须经过的城市之间的最短路,之后由小的状态向大的状态转移就好了,这题常数卡得比较紧,最短路尽量写heap+dijkstra,并且DP时判掉冗余状态,就能过了
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<vector>
#include<queue>
using namespace std;
const int maxn=20000+10;
const int maxm=1<<21;
int d[maxn],dis[23][maxm],n,m,k,f[23][23],pre[maxn],id[maxn],vis[maxn];
bool inq[23][maxm];
struct node
{
int to,cost;
};
struct arr
{
int p,s;
};
struct vv
{
int p,v;
bool operator <(const vv g)const
{
return v>g.v;
}
};
priority_queue<vv> Q;
vector<node> g[maxn];
void dijkstra(int p)
{
memset(vis,0,sizeof(vis));
memset(d,127/2,sizeof(d));
d[id[p]]=0;Q.push((vv){id[p],d[id[p]]});
while(!Q.empty())
{
vv x=Q.top();Q.pop();if(vis[x.p]) continue;
vis[x.p]=1;
for(int i=0;i<g[x.p].size();i++)
{
node e=g[x.p][i];int v=e.to;
if(d[v]>d[x.p]+e.cost)
{
d[v]=d[x.p]+e.cost;
Q.push((vv){v,d[v]});
}
}
}
for(int i=1;i<=k+1;i++)
f[p][i]=d[i];
f[p][k+2]=d[n];
}
void spfa(int p)
{
memset(d,127/2,sizeof(d));
d[id[p]]=0;queue<int> Q;Q.push(id[p]);inq[p][id[p]]=1;
while(!Q.empty())
{
int x=Q.front();Q.pop();inq[p][x]=0;
for(int i=0;i<g[x].size();i++)
{
node e=g[x][i];int v=e.to;
if(d[v]>d[x]+e.cost)
{
d[v]=d[x]+e.cost;
if(!inq[p][v])
{
inq[p][v]=1;
Q.push(v);
}
}
}
}
for(int i=1;i<=k+1;i++)
f[p][i]=d[i];
f[p][k+2]=d[n];
}
void dp()
{
memset(inq,0,sizeof(inq));queue<arr> Q;
memset(dis,127/2,sizeof(dis));dis[1][0]=0;
for(int s=0;s<(1<<k);s++)
for(int x=1;x<=k+2;x++)
for(int i=1;i<=k+2;i++)
if((pre[id[i]]&s)==pre[id[i]]&&i!=x)
{
int ns=s;
if(i>1&&i<=k+1) ns=s|(1<<(i-2));
if(dis[i][ns]>dis[x][s]+f[x][i])
dis[i][ns]=dis[x][s]+f[x][i];
}
}
int main()
{
//freopen("1097.in","r",stdin);
//freopen("1097.out","w",stdout);
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=m;i++)
{
int u,v,c;scanf("%d%d%d",&u,&v,&c);
g[u].push_back((node){v,c});
g[v].push_back((node){u,c});
}
for(int i=1;i<=k+1;i++) id[i]=i;
id[k+2]=n;
for(int i=1;i<=k+2;i++)
dijkstra(i);
int l;scanf("%d",&l);
for(int i=1;i<=l;i++)
{
int x,y;scanf("%d%d",&x,&y);
if(x<n) pre[y]+=1<<(x-2);
else pre[y]+=1<<(k+1);
}
dp();
printf("%d\n",dis[k+2][(1<<k)-1]);
return 0;
}