码迷,mamicode.com
首页 > 其他好文 > 详细

P3489 [POI2009]WIE-Hexer

时间:2020-07-26 01:58:57      阅读:90      评论:0      收藏:0      [点我收藏+]

标签:开始   continue   压缩   fine   hex   for   main   iostream   pre   

P3489:https://www.luogu.com.cn/problem/P3489
bzoj1139:https://darkbzoj.tk/problem/1139

dij 分层图最短路+状态压缩,把状态大小上限 \(2^p-1\) 写成了 \(2^{p-1}-1\),然后debug了将近一晚上。。。

由于 \(p\le 13\),而且当前能走哪些路不能走哪些,又和每一个剑的有无有关,所以我们用一个 13 为二进制数来表示当前状态下,每一个剑有没有
\(dis_{i,S}\) 表示的就是从 \(1\)\(i\),且状态为 \(S\) 所需的最短路程
答案就是 \(\min\{dis_{n,S},S< 2^p\}\)
这里为了 dij 那里处理起来方便 复制板子方便,直接将这两维用一个数表示了,具体看 id 数组

然后 dij 中的每当开始处理一个 \(u\),就用当前节点铁匠的信息,来更新 \(S\),枚举出边的时候在判断一下当前这条边能不能走就行了

应该还是挺简单
话说这题是当时刚学 dij 的时候,连堆优化都还不会,就用 dij 的标签搜进了这题,然后还码了半天,发现思路不对就直接让它进任务计划吃灰了
然后这一年多以后才想起来回来做

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<queue>
#include<iomanip>
#include<cstring>
#define reg register
#define EN std::puts("")
#define LL long long
inline int read(){
	register int x=0;register int y=1;
	register char c=std::getchar();
	while(c<‘0‘||c>‘9‘){if(c==‘-‘) y=0;c=std::getchar();}
	while(c>=‘0‘&&c<=‘9‘){x=x*10+(c^48);c=std::getchar();}
	return y?x:-x;
}
#define N 1700005
#define M 6005
struct graph{
	int fir[N],nex[M],to[M],w[M],tot;
	inline void add(int u,int v,int z){
		to[++tot]=v;w[tot]=z;
		nex[tot]=fir[u];fir[u]=tot;
	}
}G;
int n,m,p,k;
int heap[N],size;
int dis[N],in[N];
int blacksmith[N],monster[M];
int id[205][9005];
int get_i[N],get_S[N];
inline void push(int x){
	heap[++size]=x;
	reg int i=size,fa;
	while(i>1){
		fa=i>>1;
		if(dis[heap[fa]]<=dis[heap[i]]) return;
		std::swap(heap[fa],heap[i]);i=fa;
	}
}
inline int pop(){
	int ret=heap[1];heap[1]=heap[size--];
	reg int i=1,ls,rs;
	while((i<<1)<=size){
		ls=i<<1;rs=ls|1;
		if(rs<=size&&dis[heap[rs]]<dis[heap[ls]]) ls=rs;
		if(dis[heap[i]]<=dis[heap[ls]]) break;
		std::swap(heap[ls],heap[i]);i=ls;
	}
	return ret;
}
inline void dij(){
	std::memset(dis,0x3f,sizeof dis);dis[id[1][blacksmith[1]]]=0;
	push(id[1][blacksmith[1]]);in[id[1][blacksmith[1]]]=1;
	reg int u,v,S;
	while(size){
		u=pop();in[u]=0;
		S=get_S[u];
		S|=blacksmith[get_i[u]];//能打造新的剑就一定造
		for(reg int i=G.fir[get_i[u]];i;i=G.nex[i]){
			if((S&monster[i])!=monster[i]) continue;
			v=id[G.to[i]][S];
//				printf("(%d %d)=> (%d %d)\n",u,v,get_i[u],get_i[v]);
			if(dis[v]>dis[u]+G.w[i]){
				dis[v]=dis[u]+G.w[i];
				if(!in[v]) push(v),in[v]=1;
			}
		}
	}
}
int main(){
	n=read();m=read();p=read();k=read();
	for(reg int w,num,i=1;i<=k;i++){
		w=read();num=read();
		while(num--) blacksmith[w]|=(1<<(read()-1));
	}
	for(reg int i=1,u,v,w,num;i<=m;i++){
		u=read();v=read();w=read();num=read();
		G.add(u,v,w);G.add(v,u,w);
		while(num--){
			u=read();
			monster[G.tot]|=(1<<(u-1));
			monster[G.tot-1]|=(1<<(u-1));
		}
	}
	int id_=0;
	for(reg int i=1;i<=n;i++)
		for(reg int S=0;S<(1<<p);S++)
			id[i][S]=++id_,get_i[id_]=i,get_S[id_]=S;
	dij();
	int ans=1e9;
	for(reg int S=0;S<(1<<p);S++) ans=std::min(ans,dis[id[n][S]]);
	printf("%d",ans==1e9?-1:ans);
	return 0;
}

P3489 [POI2009]WIE-Hexer

标签:开始   continue   压缩   fine   hex   for   main   iostream   pre   

原文地址:https://www.cnblogs.com/suxxsfe/p/13378428.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!