• 【NOIP2017】宝藏(状态压缩,动态规划)


    【NOIP2017】宝藏(状态压缩,动态规划)

    题面

    洛谷
    题目描述

    参与考古挖掘的小明得到了一份藏宝图,藏宝图上标出了 n 个深埋在地下的宝藏屋, 也给出了这 n 个宝藏屋之间可供开发的 m 条道路和它们的长度。

    小明决心亲自前往挖掘所有宝藏屋中的宝藏。但是,每个宝藏屋距离地面都很远, 也就是说,从地面打通一条到某个宝藏屋的道路是很困难的,而开发宝藏屋之间的道路 则相对容易很多。

    小明的决心感动了考古挖掘的赞助商,赞助商决定免费赞助他打通一条从地面到某 个宝藏屋的通道,通往哪个宝藏屋则由小明来决定。

    在此基础上,小明还需要考虑如何开凿宝藏屋之间的道路。已经开凿出的道路可以 任意通行不消耗代价。每开凿出一条新道路,小明就会与考古队一起挖掘出由该条道路 所能到达的宝藏屋的宝藏。另外,小明不想开发无用道路,即两个已经被挖掘过的宝藏 屋之间的道路无需再开发。

    新开发一条道路的代价是:L*K
    L代表这条道路的长度,K代表从赞助商帮你打通的宝藏屋到这条道路起点的宝藏屋所经过的 宝藏屋的数量(包括赞助商帮你打通的宝藏屋和这条道路起点的宝藏屋) 。

    请你编写程序为小明选定由赞助商打通的宝藏屋和之后开凿的道路,使得工程总代 价最小,并输出这个最小值。
    输入输出格式
    输入格式:

    第一行两个用空格分离的正整数 n 和 m,代表宝藏屋的个数和道路数。

    接下来 m 行,每行三个用空格分离的正整数,分别是由一条道路连接的两个宝藏 屋的编号(编号为 1~n),和这条道路的长度 v。

    输出格式:

    输出共一行,一个正整数,表示最小的总代价。

    题解

    去年的题目我现在才来改。我是真的弱。。。

    感觉去年考场上想的其实已经是我现在这个方法了,只是当时对于位运算的一些操作还是不熟悉,导致了巨大的常数,导致自己(GG)。当然,考场上也没有处理(INF)的问题导致炸掉了。。。

    回归正题。

    考虑状态(f[S])表示当前已经连接了状态(S)的宝藏
    但是我们的转移和当前的层数有关,
    因此,加上一维(f[i][S])表示当前已经有(i)层,状态是(S)的最小代价
    枚举(i,S),枚举(S)的补集,考虑哪一些放在当前这一层就行了。
    时间复杂度,大概是(O(n3^n)),我不确定诶。。。

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<set>
    #include<map>
    #include<vector>
    #include<queue>
    using namespace std;
    #define ll long long
    #define RG register
    #define INF (1000000000)
    inline int read()
    {
        RG int x=0,t=1;RG char ch=getchar();
        while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
        if(ch=='-')t=-1,ch=getchar();
        while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
        return x*t;
    }
    int g[15][15],n,m;
    int f[15][1<<12],V[15];
    int p[15],lg[1<<15];
    int main()
    {
    	n=read();m=read();
    	memset(g,63,sizeof(g));
    	for(int i=1;i<=m;++i)
    	{
    		int u=read()-1,v=read()-1,w=read();
    		g[u][v]=g[v][u]=min(g[u][v],w);
    	}
    	for(int i=0;i<n;++i)lg[1<<i]=i;
    	memset(f,63,sizeof(f));
    	for(int i=0;i<n;++i)f[0][1<<i]=0;
    	for(int i=0;i<n;++i)
    		for(int j=0;j<(1<<n);++j)
    		{
    			if(f[i][j]>=INF)continue;
    			int cnt=0;
    			for(int k=0;k<n;++k)
    				if(~j&(1<<k))
    				{
    					V[k]=INF;
    					for(int a=j;a;a-=a&(-a))
    						if(g[lg[a&(-a)]][k]<INF)
    							V[k]=min(V[k],g[lg[a&(-a)]][k]*(i+1));
    					p[cnt++]=k;
    				}
    			for(int k=0;k<(1<<cnt);++k)
    			{
    				int tt=0,S=0;
    				for(int a=0;a<cnt;++a)
    					if(k&(1<<a))
    					{
    						if(V[p[a]]==INF||tt>=INF){tt=INF;break;}
    						tt+=V[p[a]];S|=1<<p[a];
    					}
    				if(tt==INF)continue;
    				f[i+1][S|j]=min(f[i+1][S|j],f[i][j]+tt);
    			}
    		}
    	int ans=INF;
    	for(int i=0;i<n;++i)ans=min(ans,f[i][(1<<n)-1]);
    	printf("%d
    ",ans);
    	return 0;
    }
    
    
  • 相关阅读:
    Ubuntu14.04升级cmake版本的方法
    在ubuntu16.04-32bits 下编译vlc和vlc-qt开源项目
    从Ubuntu 14.04 LTS版升级到Ubuntu 16.04 LTS
    如何使用Heartbeat,组建一个高可用性的mysql集群
    VLC和Qt结合编写流媒体rtsp播放器
    How to Analyze "Deadlocked Schedulers" Dumps?---WINDBG
    sqlserver-kit.org
    SQLSERVER ----improvedk
    sql server博客
    分享]国外最新安全推文整理
  • 原文地址:https://www.cnblogs.com/cjyyb/p/8672092.html
Copyright © 2020-2023  润新知