【NOIP2017】宝藏(状态压缩,动态规划)
2018-03-29 20:05
344 查看
题面
洛谷题目描述
参与考古挖掘的小明得到了一份藏宝图,藏宝图上标出了 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(n3n),我不确定诶。。。
#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\n",ans); return 0; }
相关文章推荐
- 【NOIP2017】宝藏(状态压缩,动态规划)
- NOIP 2017 Day2 题2:宝藏 状态压缩
- 【jzoj3737】【挖宝藏】【斯坦纳树】【状态压缩动态规划】
- 【jzoj4908】【NOIP2016提高组】【愤怒的小鸟】【状态压缩动态规划】
- M. Frequent Subsets Problem - 状态压缩-2017 ACM-ICPC 亚洲区(南宁赛区)网络赛
- 黑客的攻击 Hacker‘s crackdown UVA11825 状态压缩动态规划
- poj 2414 Phylogenetic Trees Inherited 完全二叉树 状态压缩位运算模拟集合操作 动态规划
- 【jzoj3632】【汕头市选2014】【舞伴】【状态压缩动态规划】
- Poj-3570 Fund Management(状态压缩动态规划)
- LOJ #2290(「THUWC 2017」随机二分图-状态压缩dp)
- [NOIP2017]宝藏 状压DP
- Luogu 1171 售货员的难题(状态压缩动态规划)
- 状态压缩动态规划(直播)
- BZOJ_4197_[Noi2015]寿司晚宴_状态压缩动态规划
- ZOJ-3697 Bad-written Number 恶心模拟-状态压缩-动态规划
- HUST1579-Portal BFS+状态压缩 2017华科现场赛-C
- 【jzoj5322】【GDOI2017模拟8.21】【小朋友】【状态压缩动态规划】
- poj3311 动态规划 轮廓线 或者状态压缩
- HDU 1074 动态规划,状态压缩
- 状态压缩动态规划