【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

 

 上面对应于题目中给出的例子。

 

Source

 

 
posted @ 2014-12-13 12:07  iwtwiioi  阅读(447)  评论(0编辑  收藏  举报