BZOJ 1097: [POI2007]旅游景点atr 状压DP+Dijkstra_heap

版权声明:https://blog.csdn.net/huashuimu2003 https://blog.csdn.net/huashuimu2003/article/details/89481492

title

BZOJ 1097
Description

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

Input

第一行包含3个整数N(2<=N<=20000),M(1<=M<=200000),K(0<=K<=20),意义如上所述。

Output

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

Sample Input

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

Sample Output

19

HINT

在这里插入图片描述
上面对应于题目中给出的例子。

analysis

首先预处理一下 K + 1 K+1 个点间的最短路。

然后状压 d p dp 一下,

状压注意去掉冗余情况不然一般会 T L E TLE

code

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
const int maxn=2e4+10,maxm=2e5+10,maxk=22;
template<typename T>inline void read(T &x)
{
	x=0;
	T f=1, ch=getchar();
	while (!isdigit(ch) && ch^'-') ch=getchar();
	if (ch=='-') f=-1, ch=getchar();
	while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
	x*=f;
}
int ver[maxm<<1],edge[maxm<<1],Next[maxm<<1],head[maxn],len;
inline void add(int x,int y,int z)
{
	ver[++len]=y,edge[len]=z,Next[len]=head[x],head[x]=len;
}

int n,m,k;
int dist[maxn],d[maxk][maxk];
bool vis[maxn];
inline void Dijkstra(int s)
{
	memset(dist,0x3f,sizeof(dist));
	memset(vis,0,sizeof(vis));
	priority_queue<pii,vector<pii>,greater<pii> >q;
	dist[s]=0;
	q.push(make_pair(0,s));
	while (!q.empty())
	{
		int x=q.top().second;
		q.pop();
		if (vis[x]) continue;
		vis[x]=1;
		for (int i=head[x]; i; i=Next[i])
		{
			int y=ver[i],z=edge[i];
			if (dist[y]>dist[x]+z)
			{
				dist[y]=dist[x]+z;
				q.push(make_pair(dist[y],y));
			}
		}
	}
	for (int i=1; i<=k+1; ++i)
		d[s][i]=dist[i];
	d[s][0]=dist[n];
}

int f[1<<20][maxk],a[maxk],ed;
inline void Dp()
{
	for (int now=0; now<=ed; ++now)
		for (int x=1; x<=k+1; ++x)
			if (f[now][x]!=-1)
				for (int i=2; i<=k+1; ++i)
				{
					int y=now|(1<<i-2);
					if ((now&a[i])==a[i])
						if (f[y][i]==-1 || f[y][i]>f[now][x]+d[x][i])
							f[y][i]=f[now][x]+d[x][i];
				}
}

int main()
{
	read(n);read(m);read(k);
	ed=(1<<k)-1;
	for (int i=1; i<=m; ++i)
	{
		int x,y,z;
		read(x);read(y);read(z);
		add(x,y,z);add(y,x,z);
	}
	for (int i=1; i<=k+1; ++i)
		Dijkstra(i);
	int x;read(x);
	for (int i=1; i<=x; ++i)
	{
		int u,v;
		read(u);read(v);
		a[v]+=(1<<u-2);
	}
	memset(f,-1,sizeof(f));
	f[0][1]=0;
	Dp();
	int ans=0x3f3f3f3f;
	for (int i=1; i<=k+1; ++i)
		if (f[ed][i]!=-1)
			ans=min(ans,f[ed][i]+d[i][0]);
	printf("%d\n",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/huashuimu2003/article/details/89481492