[bzoj1097][状压DP][最短路]旅游景点atr

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Rose_max/article/details/82894770

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,总长度为1
9。注意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

题解

发现K很小
可以搞事情
f [ i ] [ k ] f[i][k] 表示最后一个停留的位置为i,已经停留过的点的状态为k
dij出每个点的最短路
大力转移就行了.

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#include<map>
#define LL long long
#define mp(x,y) make_pair(x,y)
using namespace std;
inline int read()
{
	int f=1,x=0;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
inline void write(int x)
{
	if(x<0)putchar('-'),x=-x;
	if(x>9)write(x/10);
	putchar(x%10+'0');
}
inline void print(int x){write(x);printf(" ");}
struct qq{int x,y,next;}e[8100];int len2,last2[410];
void ins2(int x,int y){len2++;e[len2].x=x;e[len2].y=y;e[len2].next=last2[x];last2[x]=len2;}
priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > > q;
struct node{int x,y,c,next;}a[411000];int len,last[21000];
void ins(int x,int y,int c){len++;a[len].x=x;a[len].y=y;a[len].c=c;a[len].next=last[x];last[x]=len;}
int d[22][21000];bool v[21000];
void dij(int st)
{
	memset(v,false,sizeof(v));memset(d[st],63,sizeof(d[st]));
	d[st][st]=0;q.push(mp(0,st));
	while(!q.empty())
	{
		int x=q.top().second;q.pop();
		if(v[x])continue;v[x]=1;
		for(int k=last[x];k;k=a[k].next)
		{
			int y=a[k].y;
			if(d[st][y]>d[st][x]+a[k].c)
			{
				d[st][y]=d[st][x]+a[k].c;
				q.push(mp(d[st][y],y));
			}
		}
	}
}
int n,m,K,T;
int nxt[25][25],bin[30];
int ok[(1<<20)+5],ok1[22][1048576];
int f[22][1048576];
int main()
{
	bin[2]=1;for(int i=3;i<=25;i++)bin[i]=bin[i-1]<<1;
	n=read();m=read();K=read();
	for(int i=1;i<=m;i++)
	{
		int x=read(),y=read(),c=read();
		ins(x,y,c);ins(y,x,c);
	}
	if(!K)
	{
		dij(1);
		printf("%d\n",d[1][n]);return 0;
	}
	for(int i=1;i<=K+1;i++)
		dij(i);
	T=read();
	for(int i=1;i<=T;i++)
	{
		int x=read(),y=read();
		ins2(y,x);nxt[x][y]=1;
	}
	ok[0]=1;
	for(int i=0;i<bin[K+2];i++)
		if(ok[i])
			for(int j=2;j<=K+1;j++)if(!(i&bin[j]))
			{
				bool tf=true;
				for(int k=last2[j];k;k=e[k].next)if(!(i&bin[e[k].y])){tf=false;break;}
				ok[i|bin[j]]=tf;ok1[j][i]=tf;
			}
	memset(f,63,sizeof(f));
	for(int i=2;i<=K+1;i++)
		if(ok[bin[i]])f[i][bin[i]]=d[1][i];
	for(int i=1;i<bin[K+2];i++)
		if(ok[i])
			for(int j=2;j<=K+1;j++)if(!(i&bin[j])&&ok1[j][i])
			{
				for(int k=2;k<=K+1;k++)if(i&bin[k])
					f[j][i|bin[j]]=min(f[j][i|bin[j]],f[k][i]+d[k][j]);
			}
	int ans=999999999;
	for(int i=2;i<=K+1;i++)
		ans=min(ans,f[i][bin[K+2]-1]+d[i][n]);
	printf("%d\n",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Rose_max/article/details/82894770