D. 旅游景点 Tourist Attractions 状压DP

题目描述

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需要的。

输入格式

第一行包含3个整数N(2<=N<=20000),M(1<=M<=200000),K(0<=K<=20),意义如上所述。以下M行,每行包含3个整数X,y,z,(1<=x,y<=n,0<z<=1000);

接下来一行,包含一个整数q,表示有q个限制条件(0<=q<n)。以下q行,每行两个整数f,l(1<=l,f<=n),表示在f停留的时候要在l之前。

输出格式

只包含一行,包含一个整数,表示最短的旅行距离。

样例

样例输入

8 15 4
1 2 3
1 3 4
1 4 4
1 6 2
1 7 3
2 3 6
2 4 2
2 5 2
3 4 3
3 6 3
3 8 6
4 5 2
4 8 6
5 7 4
5 8 6
3
2 3
3 4
3 5

样例输出

19

 

#include<bits/stdc++.h>
#define re register int
#define N 200100
#define M 400010
#define INF 10000000
using namespace std;
int n,m,k;
int tot,ans;
int head[N];
int dis[31][N];
int fa[31];
int f[1<<21][22];
bool vis[N];
struct TU
{
	int s,u;
	friend bool operator < (TU x,TU y)
	{
		return x.u>y.u;
	}
}t;
priority_queue<TU> Q;
struct CUN
{
	int fr,to,w,next;
}use[M<<4];
void add(int x,int y,int z)
{
	use[++tot].fr=x;
	use[tot].to=y;
	use[tot].w=z;
	use[tot].next=head[x];
	head[x]=tot;
}
void dj(int st)
{
	memset(vis,0,sizeof(vis));
	while(!Q.empty())
		Q.pop();
	dis[st][st]=0;
	t.s=st;
	t.u=0;
	Q.push(t);
	int x,y,p;
	while(!Q.empty())
	{
		x=Q.top().s;
		y=Q.top().u;
		Q.pop();
		if(!vis[x])
		{
			vis[x]=1;
			for(re i=head[x];i;i=use[i].next)
			{
				p=use[i].to;
				t.s=p;
				if(dis[st][p]>dis[st][x]+use[i].w)
				{
					dis[st][p]=dis[st][x]+use[i].w;
					t.u=dis[st][p];
					Q.push(t);
				}
			}
		}
	}
}
signed main()
{
	scanf("%d%d%d",&n,&m,&k);
	int a,b,c,q;
	for(re i=1;i<=m;i++)
	{
		scanf("%d%d%d",&a,&b,&c);
		add(a,b,c);
		add(b,a,c);
	}
	memset(dis,0x7f,sizeof(dis));
	for(re i=1;i<=k+1;i++)
		dj(i);
	scanf("%d",&q);
	while(q--)
	{
		scanf("%d%d",&a,&b);
		fa[b]|=(1<<(a-2));
	}
	if(k==0)
	{
		printf("%d",dis[1][n]);
		return 0;
	}
	memset(f,0x3f,sizeof(f));
	f[0][1]=0;
	for(re i=2;i<=k+1;i++)
	{
		if(!fa[i])
			f[1<<(i-2)][i]=dis[1][i];
	}
	for(re i=1;i<(1<<k);i++)
	{
		for(re j=0;j<k;j++)
		{
			if((!(i&(1<<j))))
				continue;
			for(re t=0;t<k;t++)
			{
				if((i&(1<<t))||(i|fa[t+2])!=i)
					continue;
				f[i|(1<<t)][t+2]=min(f[i|(1<<t)][t+2],f[i][j+2]+dis[j+2][t+2]);
			}
		}
	}
	ans=INF;
	for(re i=2;i<=k+1;i++)
		ans=min(ans,f[(1<<k)-1][i]+dis[i][n]);
	printf("%d",ans);
	return 0;
}
posted @ 2021-04-24 18:33  WindZR  阅读(126)  评论(0编辑  收藏  举报