zoukankan      html  css  js  c++  java
  • 【bzoj1097】[POI2007]旅游景点atr 状压dp+堆优化Dijkstra

    题目描述

    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),意义如上所述。

    输出

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

    样例输入

    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


    题解

    状压dp+堆优化Dijkstra

    题目给出$kle 20$及每个点经过一次,显然状压dp。

    不过由于点数非常多,因此不能以点数为状态,而是以关键点为状态。

    设$f[i][j]$表示经过的点的状态为$i$,当前所在点为第$j$个关键点的最小路程。

    考虑枚举下一个关键点,所走的路径一定是它们之间的最短路。

    所以预处理出$1...k+1$到所有点的最短路,然后初始状态为$f[1<<i][i]=dis[1][i]$,转移时加上最短距离。

    最后的答案就是$min(f[(1<<k)-1][i]+dis[i][n])$。

    时间复杂度$O(k(n+m)log n+2^k·k^2)$

    #include <queue>
    #include <cstdio>
    #include <cstring>
    #include <utility>
    #define N 20010
    #define M 400010
    using namespace std;
    typedef pair<int , int> pr;
    priority_queue<pr> q;
    int head[N] , to[M] , len[M] , next[M] , cnt , dis[22][N] , vis[N] , lim[N] , f[1 << 20][21];
    void add(int x , int y , int z)
    {
    	to[++cnt] = y , len[cnt] = z , next[cnt] = head[x] , head[x] = cnt;
    }
    void dijkstra(int s)
    {
    	int i , x;
    	memset(dis[s] , 0x3f , sizeof(dis[s])) , memset(vis , 0 , sizeof(vis));
    	dis[s][s] = 0 , q.push(pr(0 , s));
    	while(!q.empty())
    	{
    		x = q.top().second , q.pop();
    		if(vis[x]) continue;
    		vis[x] = 1;
    		for(i = head[x] ; i ; i = next[i])
    			if(dis[s][to[i]] > dis[s][x] + len[i])
    				dis[s][to[i]] = dis[s][x] + len[i] , q.push(pr(-dis[s][to[i]] , to[i]));
    	}
    }
    int main()
    {
    	int n , m , d , p , i , j , k , x , y , z , ans = 1 << 30;
    	scanf("%d%d%d" , &n , &m , &d);
    	for(i = 1 ; i <= m ; i ++ ) scanf("%d%d%d" , &x , &y , &z) , add(x , y , z) , add(y , x , z);
    	for(i = 1 ; i <= d + 1 ; i ++ ) dijkstra(i);
    	scanf("%d" , &p);
    	for(i = 1 ; i <= p ; i ++ ) scanf("%d%d" , &x , &y) , lim[y - 1] |= (1 << (x - 2));
    	if(!d)
    	{
    		printf("%d
    " , dis[1][n]);
    		return 0;
    	}
    	memset(f , 0x3f , sizeof(f));
    	for(i = 1 ; i <= d ; i ++ )
    		if(!lim[i])
    			f[1 << (i - 1)][i] = dis[1][i + 1];
    	for(i = 1 ; i < 1 << d ; i ++ )
    		for(j = 1 ; j <= d ; j ++ )
    			if(i & (1 << (j - 1)))
    				for(k = 1 ; k <= d ; k ++ )
    					if(!(i & (1 << (k - 1))) && !(~i & lim[k]))
    						f[i | (1 << (k - 1))][k] = min(f[i | (1 << (k - 1))][k] , f[i][j] + dis[j + 1][k + 1]);
    	for(i = 1 ; i <= d ; i ++ ) ans = min(ans , f[(1 << d) - 1][i] + dis[i + 1][n]);
    	printf("%d
    " , ans);
    	return 0;
    }
    

     

  • 相关阅读:
    ABP学习之路--切换mysql数据库
    关于网站发布后站点访问404的问题
    关于COOKIE在本地可以正常写入发布后不能写入浏览器的问题
    关于CSS层叠样式(颜色+边框+文本属性)
    HTML 自学笔记(HTML框架+表单设计)
    HTML 自学笔记(HTML表格相关标记)
    HTML 自学笔记(HTML的图像标记+超链接的使用)
    HTML 自学笔记(HTML的基本结构+文档设置标记)
    .net的页面在大并发下偶尔出现503错误
    WebService:The remote server returned an error: (400) Bad Request
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/7434536.html
Copyright © 2011-2022 走看看