【BZOJ】1097: [POI2007]旅游景点atr(spfa+状压dp)

http://www.lydsy.com/JudgeOnline/problem.php?id=1097

首先还是我很sb。。。。想到了分层图想不到怎么串起来,,,以为用拓扑序搞转移,,后来感到不行。。。

QAQ

这种数据那么小,有明确的依赖性为嘛我想不到状压。。。(准确的说是没想到状压和分层图一起做。。。。

还有一个。。。。。。。为什么递推不行。。。(还是我写挫了。。。老wa。。)非得记忆化。。。。。。

(其实记忆化的话能省点不必要的状态吧。。。

。。。。

还有。。。和zyf一样,被卡在了。。!(s&(1<<(v-1)))。。。。。不去掉就tle。。也是喜闻乐见。。。

QAQ

(然后我spfa的vis标记打错了。。。。。。。调了好久。。QAQ

#include <cstdio>

#include <cstring>

#include <cmath>

#include <string>

#include <iostream>

#include <algorithm>

#include <queue>

#include <set>

#include <map>

using namespace std;

typedef long long ll;

#define rep(i, n) for(int i=0; i<(n); ++i)

#define for1(i,a,n) for(int i=(a);i<=(n);++i)

#define for2(i,a,n) for(int i=(a);i<(n);++i)

#define for3(i,a,n) for(int i=(a);i>=(n);--i)

#define for4(i,a,n) for(int i=(a);i>(n);--i)

#define CC(i,a) memset(i,a,sizeof(i))

#define read(a) a=getint()

#define print(a) printf("%d", a)

#define dbg(x) cout << (#x) << " = " << (x) << endl

#define error(x) (!(x)?puts("error"):0)

#define rdm(x, i) for(int i=ihead[x]; i; i=e[i].next)

#define grdm(g, x, i) for(int i=g.ihead[x]; i; i=g.e[i].next)

inline const int getint() { int r=0, k=1; char c=getchar(); for(; c<'0'||c>'9'; c=getchar()) if(c=='-') k=-1; for(; c>='0'&&c<='9'; c=getchar()) r=r*10+c-'0'; return k*r; }



const int N=50005, oo=0x3f3f3f3f;

int d[22][N], vis[N], q[N], ihead[N], cnt, n, m, k;

struct dat { int next, to, w; }e[N*10*2];

void add1(int u, int v, int w) { e[++cnt].next=ihead[u]; ihead[u]=cnt; e[cnt].to=v; e[cnt].w=w; }

void add(int u, int v, int w) { add1(u, v, w); add1(v, u, w); }

void spfa(int s, int *f) {

	memset(vis, 0, sizeof(int)*(n));

	memset(f, 0x3f, sizeof(int)*(n));

	int front=0, tail=0;

	f[s]=0; q[tail++]=s; vis[s]=1;

	while(front!=tail) {

		int u=q[front++], v; if(front==N) front=0; vis[u]=0;

		rdm(u, i) if(f[v=e[i].to]>f[u]+e[i].w) {

			f[v]=f[u]+e[i].w;

			if(!vis[v]) {

				vis[v]=1;

				if(f[q[front]]>f[v]) {

					--front; if(front<0) front+=N;

					q[front]=v;

				}

				else {

					q[tail++]=v; if(tail==N) tail=0;

				}

			}

		}

	}

}

int ans[21][1<<(20)], b[22], all;

int dfs(int u, int s) {

	if(ans[u][s]>=0) return ans[u][s];

	if(s==all) return d[u][n-1];

	int &a=ans[u][s]; a=oo;

	for1(v, 1, k) if((b[v]&s)==b[v]) a=min(a, d[u][v]+dfs(v, s|(1<<(v-1))));

	return a;

}

int main() {

	read(n); read(m); read(k);

	for1(i, 1, m) { int u=getint(), v=getint(), w=getint(); add(u-1, v-1, w); }

	for1(i, 0, k) spfa(i, d[i]);

	read(m);

	for1(i, 1, m) { int u=getint(), v=getint(); b[v-1]|=(1<<(u-2)); }

	all=(1<<k)-1;

	CC(ans, -1);

	printf("%d\n", dfs(0, 0));

	return 0;

}

  

 


 

 

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),意义如上所述。以下M行,每行包含3个整数X,Y,Z,(1<=X

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

 

【BZOJ】1097: [POI2007]旅游景点atr(spfa+状压dp) 上面对应于题目中给出的例子。

 

Source

 

 

你可能感兴趣的:(SPFA)