动态规划——状压树形
Posted SummerSky
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了动态规划——状压树形相关的知识,希望对你有一定的参考价值。
问题 A: 铺砖块
时间限制: 1 Sec 内存限制: 128 MB题目描述
现有n*m的一块地板,需要用1*2的砖块去铺满,中间不能留有空隙。问这样方案有多少种
输入
输入n,m(1<=n, m<=11)
有多组输入数据,以m=n=0结束
输出
输出铺砖块的方案数
样例输入
样例输出
1 #include<iostream> 2 #include<algorithm> 3 #include<cstdio> 4 #include<cstring> 5 #include<cmath> 6 #include<cstdlib> 7 #include<vector> 8 using namespace std; 9 typedef long long ll; 10 typedef long double ld; 11 typedef pair<int,int> pr; 12 const double pi=acos(-1); 13 #define rep(i,a,n) for(int i=a;i<=n;i++) 14 #define per(i,n,a) for(int i=n;i>=a;i--) 15 #define Rep(i,u) for(int i=head[u];i;i=Next[i]) 16 #define clr(a) memset(a,0,sizeof(a)) 17 #define pb push_back 18 #define mp make_pair 19 #define fi first 20 #define sc second 21 #define pq priority_queue 22 #define pqb priority_queue <int, vector<int>, less<int> > 23 #define pqs priority_queue <int, vector<int>, greater<int> > 24 #define vec vector 25 ld eps=1e-9; 26 ll pp=1000000007; 27 ll mo(ll a,ll pp){if(a>=0 && a<pp)return a;a%=pp;if(a<0)a+=pp;return a;} 28 ll powmod(ll a,ll b,ll pp){ll ans=1;for(;b;b>>=1,a=mo(a*a,pp))if(b&1)ans=mo(ans*a,pp);return ans;} 29 int dx[5]={0,-1,1,0,0},dy[5]={0,0,0,-1,1}; 30 ll read(){ ll ans=0; char last=‘ ‘,ch=getchar(); 31 while(ch<‘0‘ || ch>‘9‘)last=ch,ch=getchar(); 32 while(ch>=‘0‘ && ch<=‘9‘)ans=ans*10+ch-‘0‘,ch=getchar(); 33 if(last==‘-‘)ans=-ans; return ans; 34 } 35 long long dp[12][3000],p[3000]; 36 int main() 37 { 38 int n,m; 39 while (~scanf("%d%d",&n,&m)){ 40 if (n==0 && m==0) break; 41 memset(dp,0,sizeof(dp)); 42 memset(p,0,sizeof(p)); 43 int k=1<<m; p[0]=1; 44 for (int i=1;i<=k;i++){ 45 int t=i&(-i); 46 if (i&(t+t)) p[i]=p[i-(t+t+t)]; 47 } 48 dp[0][k-1]=1; 49 for (int i=0;i<n;i++) 50 for (int j=0;j<k;j++) 51 if (dp[i][j]){ 52 for (int z=0;z<k;z++) 53 if ((z&j)==z && p[z]) dp[i+1][(k-1-j)|z]+=dp[i][j]; 54 } 55 printf("%lld\n",dp[n][k-1]); 56 } 57 return 0; 58 }
问题 B: 导游2
时间限制: 1 Sec 内存限制: 128 MB题目描述
宁波市的中小学生们在镇海中学参加程序设计比赛之余,热情的主办方邀请同学们参观镇海中学内的各处景点,已知镇海中学内共有n处景点。现在有n位该校的学生志愿承担导游和讲解任务。每个学生志愿者对各个景点的熟悉程度是不同的,如何将n位导游分配至n处景点,使得总的熟悉程度最大呢?要求每个景点处都有一个学生导游。
输入
有若干行:
第一行只有一个正整数n,表示有n个景点和n个学生导游。
第二行至第n+1行共n行,每行有n个以空格分隔的正整数。第i+1行的第j个数k(1≤k≤1000),表示第i个学生导游对景点j的熟悉程度为k。
输出
只有一行,该行只有一个正整数,表示求得的熟悉程度之和的最大值。
样例输入
样例输出
提示
【样例说明】
第1个学生负责第3个景点,第2个学生负责第1个景点,第3个学生负责第2个景点时,熟悉程度总和为24,达到最大值。
【数据限制】
50%的数据,1≤n≤9;100%的数据,1≤n≤17。
同上,记下前面的状态,转移随意,,
1 #include<iostream> 2 #include<algorithm> 3 #include<cstdio> 4 #include<cstring> 5 #include<cmath> 6 #include<cstdlib> 7 #include<vector> 8 using namespace std; 9 typedef long long ll; 10 typedef long double ld; 11 typedef pair<int,int> pr; 12 const double pi=acos(-1); 13 #define rep(i,a,n) for(int i=a;i<=n;i++) 14 #define per(i,n,a) for(int i=n;i>=a;i--) 15 #define Rep(i,u) for(int i=head[u];i;i=Next[i]) 16 #define clr(a) memset(a,0,sizeof(a)) 17 #define pb push_back 18 #define mp make_pair 19 #define fi first 20 #define sc second 21 #define pq priority_queue 22 #define pqb priority_queue <int, vector<int>, less<int> > 23 #define pqs priority_queue <int, vector<int>, greater<int> > 24 #define vec vector 25 ld eps=1e-9; 26 ll pp=1000000007; 27 ll mo(ll a,ll pp){if(a>=0 && a<pp)return a;a%=pp;if(a<0)a+=pp;return a;} 28 ll powmod(ll a,ll b,ll pp){ll ans=1;for(;b;b>>=1,a=mo(a*a,pp))if(b&1)ans=mo(ans*a,pp);return ans;} 29 void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); } 30 //void add(int x,int y,int z){ v[++e]=y; next[e]=head[x]; head[x]=e; cost[e]=z; } 31 int dx[5]={0,-1,1,0,0},dy[5]={0,0,0,-1,1}; 32 ll read(){ ll ans=0; char last=‘ ‘,ch=getchar(); 33 while(ch<‘0‘ || ch>‘9‘)last=ch,ch=getchar(); 34 while(ch>=‘0‘ && ch<=‘9‘)ans=ans*10+ch-‘0‘,ch=getchar(); 35 if(last==‘-‘)ans=-ans; return ans; 36 } 37 int dp[200000],a[20][20]; 38 int main() 39 { 40 int n=read(); 41 for (int i=1;i<=n;i++) 42 for (int j=1;j<=n;j++) a[i][j]=read(); 43 dp[0]=0; int K=1<<n; 44 for (int j=1;j<K;j++){ 45 int num=0; 46 for (int k=1;k<=n;k++) 47 if (j&(1<<k-1)) num++; 48 for (int k=1;k<=n;k++) 49 if (j&(1<<(k-1))) 50 dp[j]=max(dp[j],dp[j-(1<<(k-1))]+a[num][k]); 51 } 52 printf("%d",dp[K-1]); 53 return 0; 54 }
问题 C: 天上掉Pizza
时间限制: 3 Sec 内存限制: 128 MB题目描述
输入
有多组输入数据。
每组输入数据第一行为m(1<=m<=15).
接下来m行,每行前3个数pi,ai,ni(1<=pi<=10000,1<=ai<=10000,0<=nipi为编号为i的Pizza的价格,ai为编号为i的Pizza的面积,ni为购买i号Pizza能得到ni张优惠券
接下来ni*2个数,分别表示该张优惠券对xi号Pizza打折(1<=xj<=m,i<>xj),折扣为yj(1<=yj<=50)
输入以m=0结束。
输出
输出购买m个Pizza中某一些的最低单位面积价格。保留4位小数。
(如果一个Pizza原价10,得到了一张50和一张20的优惠券,那么购买它实际所需的价值就是10*0.5*0.8=4)
样例输入
样例输出
提示
Pizza可以不全部购买
令dp[i]为以i为状态时用的最少的钱,而价格是固定的,我们只需要记录最小价格就好了,
1 #include<iostream> 2 #include<algorithm> 3 #include<cstdio> 4 #include<cstring> 5 #include<cmath> 6 #include<cstdlib> 7 #include<vector> 8 using namespace std; 9 typedef long long ll; 10 typedef long double ld; 11 typedef pair<int,int> pr; 12 const double pi=acos(-1); 13 #define rep(i,a,n) for(int i=a;i<=n;i++) 14 #define per(i,n,a) for(int i=n;i>=a;i--) 15 #define Rep(i,u) for(int i=head[u];i;i=Next[i]) 16 #define clr(a) memset(a,0,sizeof(a)) 17 #define pb push_back 18 #define mp make_pair 19 #define fi first 20 #define sc second 21 #define pq priority_queue 22 #define pqb priority_queue <int, vector<int>, less<int> > 23 #define pqs priority_queue <int, vector<int>, greater<int> > 24 #define vec vector 25 ld eps=1e-9; 26 ll pp=1000000007; 27 ll mo(ll a,ll pp){if(a>=0 && a<pp)return a;a%=pp;if(a<0)a+=pp;return a;} 28 ll powmod(ll a,ll b,ll pp){ll ans=1;for(;b;b>>=1,a=mo(a*a,pp))if(b&1)ans=mo(ans*a,pp);return ans;} 29 void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); } 30 //void add(int x,int y,int z){ v[++e]=y; next[e]=head[x]; head[x]=e; cost[e]=z; } 31 int dx[5]={0,-1,1,0,0},dy[5]={0,0,0,-1,1}; 32 ll read(){ ll ans=0; char last=‘ ‘,ch=getchar(); 33 while(ch<‘0‘ || ch>‘9‘)last=ch,ch=getchar(); 34 while(ch>=‘0‘ && ch<=‘9‘)ans=ans*10+ch-‘0‘,ch=getchar(); 35 if(last==‘-‘)ans=-ans; return ans; 36 } 37 #define N 16 38 int p[N],a[N],nu[N],t[N][N+N+5],t_[N][N+N+5]; 39 double f[N],dp[1<<N]; 40 int main() 41 { 42 int n,suma=0; 43 while (~scanf("%d",&n)){ 44 if (n==0) break; 45 memset(p,0,sizeof(p)); 46 memset(a,0,sizeof(a)); 47 memset(nu,0,sizeof(nu)); 48 memset(t,0,sizeof(t)); 49 for (int i=1;i<(1<<N);i++) dp[i]=1e9; 50 for (int i=1;i<=n;i++){ 51 p[i]=read(),a[i]=read(),nu[i]=read(); 52 for (int j=1;j<=nu[i];j++) t[i][j]=read(),t_[i][j]=read(); 53 } 54 int K=1<<n; dp[0]=0; 55 for (int i=0;i<K;i++){ 56 for (int j=1;j<=n;j++) f[j]=1; 57 for (int j=1;j<=n;j++) 58 if (i&(1<<(j-1))) { 59 for (int k=1;k<=nu[j];k++) 60 f[t[j][k]]=f[t[j][k]]*(100-t_[j][k])/100; 61 } 62 for (int j=1;j<=n;j++) 63 if ((i&(1<<(j-1)))==0) 64 dp[i+(1<<(j-1))]=min(dp[i+(1<<(j-1))],dp[i]+1.0*p[j]*f[j]); 65 } 66 double ans=1e9; 67 for (int i=0;i<K;i++){ 68 suma=0; 69 for (int j=1;j<=n;j++) 70 if (i&(1<<(j-1))) suma+=a[j]; 71 ans=min(ans,dp[i]/suma); 72 } 73 printf("%.4f\n",ans); 74 } 75 return 0; 76 }
问题 D: 稀有矿井
时间限制: 1 Sec 内存限制: 128 MB题目描述
XYZ公司已在沿太平洋东海岸位于不同地区的几个岛屿发现了5种稀有的矿藏。该公司认为,这将是一个获利最好的机会。然而,由于金融危机,该公司并没有足够的人手和金钱在所有岛屿上建立矿田。因此,公司委员会选择了一些有较高的矿石储量岛屿,并派出一名调查员对这些岛屿制作了岛上的矿石分布调查。调查结果显示,每个岛上有许多连接在一起的村庄。由于耗费时间,调查员并没有记录的地图中的所有路径。只是记下了一条到达每个村庄的路径,从一个村庄到达另一个,有一个且只有一条路径(地图绘制像一棵树)。
该公司计划在每个岛屿的其中一个村庄建立分工厂。所有在岛上不同地方挖来的5种稀有矿产将被发送到这个分工厂,后成为一个复合金属。因此途径的道路必须被重修过,才能通过数量庞大的车队。为了尽量减少对道路交通的建设成本,公司决定扩大原有的路径,而不是兴建新的道路。此外,该公司决定兴建村庄的矿田,以确保他们的工人可以进入采矿。 (如果子工厂坐落在一个村庄中,矿田也可以建在该村庄。)
由于这些岛屿的矿石储量非常高,每一种罕见的矿物只需要一矿田开采即可。鉴于目前所选择的岛屿的地图,你需要找到在每个岛上的建立子工厂的最优村庄,并从该村庄开始扩展道路,以采集所有5种稀有的矿产。
输入
第一行,包含一个整数T,表示岛屿的数目。(1<=Num<=50)
每组测试数据,第一行一个整数N(5<=N<=1000)。表示岛上村庄的个数。
接下来一行,N个数,m1, m2, ... mn(0<=mi<=5),表示第i个村庄所拥有的稀有矿藏的种类,0表示该村庄没有稀有矿藏(每一个村庄至多只有一种矿藏)。
接下来N-1行,描述了这个岛上连接N个村庄的地图。
每行三个数,x,y,d(1<=x, y<=n, 1<=d<=10000), 表示从x和y两个村庄之间有一条距离为d的路。
输出
每行输出一个整数。在每个岛上所需的最少扩建道路的长度。
样例输入
样例输出
1 #include<iostream> 2 #include<algorithm> 3 #include<cstdio> 4 #include<cstring> 5 #include<cmath> 6 #include<cstdlib> 7 #include<vector> 8 using namespace std; 9 typedef long long ll; 10 typedef long double ld; 11 typedef pair<int,int> pr; 12 const double pi=acos(-1); 13 #define rep(i,a,n) for(int i=a;i<=n;i++) 14 #define per(i,n,a) for(int i=n;i>=a;i--) 15 #define Rep(i,u) for(int i=head[u];i;i=Next[i]) 16 #define clr(a) memset(a,0,sizeof(a)) 17 #define pb push_back 18 #define mp make_pair 19 #define fi first 20 #define sc second 21 #define pq priority_queue 22 #define pqb priority_queue <int, vector<int>, less<int> > 23 #define pqs priority_queue <int, vector<int>, greater<int> > 24 #define vec vector 25 ld eps=1e-9; 26 ll pp=1000000007; 27 ll mo(ll a,ll pp){if(a>=0 && a<pp)return a;a%=pp;if(a<0)a+=pp;return a;} 28 ll powmod(ll a,ll b,ll pp){ll ans=1;for(;b;b>>=1,a=mo(a*a,pp))if(b&1)ans=mo(ans*a,pp);return ans;} 29 void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); } 30 #define N 2000 31 int e,v[N],next[N],head[N],cost[N]; 32 void add(int x,int y,int z){ v[++e]=y; next[e]=head[x]; head[x]=e; cost[e]=z; } 33 int dx[5]={0,-1,1,0,0},dy[5]={0,0,0,-1,1}; 34 ll read(){ ll ans=0; char last=‘ ‘,ch=getchar(); 35 while(ch<‘0‘ || ch>‘9‘)last=ch,ch=getchar(); 36 while(ch>=‘0‘ && ch<=‘9‘)ans=ans*10+ch-‘0‘,ch=getchar(); 37 if(last==‘-‘)ans=-ans; return ans; 38 } 39 int s[N],flag[N],f[N][32]; 40 void dfs(int x){ 41 flag[x]=0; 42 f[x][(1<<(s[x]-1))]=0; 43 int e=head[x]; 44 while (e!=-1){ 45 int v_=v[e],c_=cost[e]; 46 if (flag[v_]){ 47 dfs(v_); 48 for (int i=0;i<=31;i++) 49 for (int j=0;j<=31;j++) 50 f[x][i|j]=min(f[x][i|j],f[x][i]+f[v_][j]+c_); 51 } 52 e=next[e]; 53 } 54 } 55 int main() 56 { 57 int T=read(); 58 while (T--){ 59 int n=read(); 60 memset(head,255,sizeof(head)); e=0; 61 for (int i=1;i<=n;i++) s[i]=read(),flag[i]=1; 62 for (int i=1;i<=n;i++) 63 for (int j=0;j<=31;j++) f[i][j]=1e9; 64 for (int i=1;i<=n-1;i++){ 65 int a=read(),b=read(),c=read(); 66 add(a,b,c); 67 add(b,a,c); 68 } 69 dfs(1); 70 int ans=1e9; 71 for (int i=1;i<=n;i++) ans=min(ans,f[i][31]); 72 printf("%d\n",ans); 73 } 74 return 0; 75 }
问题 E: 炮兵阵地
时间限制: 1 Sec 内存限制: 128 MB题目描述
输入
输出
文件仅在第一行包含一个整数K,表示最多能摆放的炮兵部队的数量。
样例输入
样例输出
1 #include<iostream> 2 #include<algorithm> 3 #include<cstdio> 4 #include<cstring> 5 #include<cmath> 6 #include<cstdlib> 7 #include<vector> 8 using namespace std; 9 //typedef long long ll; 10 typedef long double ld; 11 typedef pair<int,int> pr; 12 const double pi=acos(-1); 13 #define rep(i,a,n) for(int i=a;i<=n;i++) 14 #define per(i,n,a) for(int i=n;i>=a;i--) 15 #define Rep(i,u) for(int i=head[u];i;i=Next[i]) 16 #define clr(a) memset(a,0,sizeof(a)) 17 #define pb push_back 18 #define mp make_pair 19 #define fi first 20 #define sc second 21 #define pq priority_queue 22 #define pqb priority_queue <int, vector<int>, less<int> > 23 #define pqs priority_queue <int, vector<int>, greater<int> > 24 #define vec vector 25 ld eps=1e-9; 26 //ll pp=1000000007; 27 //ll mo(ll a,ll pp){if(a>=0 && a<pp)return a;a%=pp;if(a<0)a+=pp;return a;} 28 //ll powmod(ll a,ll b,ll pp){ll ans=1;for(;b;b>>=1,a=mo(a*a,pp))if(b&1)ans=mo(ans*a,pp);return ans;} 29 //void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); } 30 //void add(int x,int y,int z){ v[++e]=y; next[e]=head[x]; head[x]=e; cost[e]=z; } 31 //int dx[5]={0,-1,1,0,0},dy[5]={0,0,0,-1,1}; 32 int read(){ int ans=0; char last=‘ ‘,ch=getchar(); 33 while(ch<‘0‘ || ch>‘9‘)last=ch,ch=getchar(); 34 while(ch>=‘0‘ && ch<=‘9‘)ans=ans*10+ch-‘0‘,ch=getchar(); 35 if(last==‘-‘)ans=-ans; return ans; 36 } 37 #define N 2000 38 int l[N],ll[N],dp[N][N],dp_[N][N],now[N],l_,ll_,n_,num[N]; 39 char a[102][12]; 40 void dfs(int x,int m,int t,int v,int p){ 41 if(t>=m){now[++n_]=v;num[n_]=p;return;} 42 if(a[x][t]==‘P‘) dfs(x,m,t+3,v|(1<<t),p+1); 43 dfs(x,m,t+1,v,p); 44 } 45 int main() 46 { 47 int n=read(),m=read(); 48 for (int i=1;i<=n;i++) scanf("%s",a[i]); 49 l[1]=ll[1]=dp_[1][1]=0; l_=ll_=1; 50 for (int k=1;k<=n;k++){ 51 memset(now,0,sizeof(now)); 52 memset(num,0,sizeof(num)); n_=0; 53 dfs(k,m,0,0,0); 54 for(int i=1;i<=n_;++i) 55 for(int j=1;j<=l_;++j)dp[i][j]=0; 56 for (int i=1;i<=n_;i++) 57 for (int j=1;j<=l_;j++) 58 for (int t=1;t<=ll_;t++) 59 if (!(now[i] & l[j]) && !(now[i] & ll[t])){ 60 dp[i][j]=max(dp[i][j],dp_[j][t]+num[i]); 61 } 62 for(int i=1;i<=n_;++i) 63 for(int j=1;j<=l_;++j) dp_[i][j]=dp[i][j]; 64 for (int i=1;i<=l_;i++) ll[i]=l[i]; ll_=l_; 65 for (int i=1;i<=n_;i++) l[i]=now[i]; l_=n_; 66 } 67 int ans=0; 68 for (int i=1;i<=l_;i++) 69 for (int j=1;j<=ll_;j++) ans=max(ans,dp_[i][j]); 70 printf("%d\n",ans); 71 return 0; 72 }
以上是关于动态规划——状压树形的主要内容,如果未能解决你的问题,请参考以下文章