• P3489 [POI2009]WIE-Hexer


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

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

    由于 (ple 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)
    ",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;
    }
    
    
  • 相关阅读:
    PyQt5经典案例
    JS实现深拷贝(解决循环引用等问题)
    React/Vue里的key到底有什么用?看完这篇你就知道了!(附demo代码)
    linux盘符操作命令
    Ubuntu20.04下安装opencv for C++
    数字图像处理-python随机噪声、高斯噪声和椒盐噪声实现
    数字图像处理-(1)pyqt页面
    数字图像处理-Python读取BMP文件
    docker笔记
    CentOS7安装GO
  • 原文地址:https://www.cnblogs.com/suxxsfe/p/13378428.html
Copyright © 2020-2023  润新知