2017 暑假艾教集训 day2
来源:互联网 发布:东方有线网络缴费 编辑:程序博客网 时间:2024/05/24 05:16
练习题 :https://cn.vjudge.net/contest/175510#overview
CTSC 拯救大兵瑞恩
做法:状压BFS,每个节点加一个当前所有的钥匙数,然后进行普通的BFS即可
POJ 2411
做法:轮廓线 状压经典题,先DFS出 s 状态和它的父亲 pre ,每次转移 dp[i][s]+=dp[i-1][pre];
DFS时 每次有横着放和竖着放, 规定横着放全为1,而竖着放上面为1 。 其余为0.
优化: DFS时 m 越大,深度越高所以 m 为min (n,m)
#include <iostream>#include <stdio.h>#include <algorithm>#include <string.h>using namespace std;int n,m;int cnt;int path[3000][2];int dp[11][(1<<5)];void dfs(int pos,int now,int pre){ if(pos>m) return; if(pos==m) { path[cnt][0]=now; path[cnt++][1]=pre; } dfs(pos+2,now<<2|3,pre<<2|3); dfs(pos+1,now<<1|1,pre<<1); dfs(pos+1,now<<1,pre<<1|1);}int main(){ while(scanf("%d%d",&n,&m)!=EOF) { if(n==0 && m==0) break; if(n%2==1 && m%2==1) { printf("0\n"); continue; } if(m>n) swap(n,m); cnt=0; dfs(0,0,0); memset(dp,0,sizeof(dp)); dp[0][(1<<m)-1]=1; for(int i=1;i<=n;++i) { for(int j=0;j<cnt;++j) { dp[i][path[j][0]]+=dp[i-1][path[j][1]]; } } printf("%d\n",dp[n][(1<<m)-1]); } return 0;}
HDU 1565
做法:状压DP,如果直接存(1<<20)或者直接枚举的话 时间和空间浪费很大。 所以我们先用 i&(i<<1) || i&(i>>1) 选取行的可选状态, 会大大降低复杂度。 然后每次转移的时候 判断一下 way[k] & way[j] 即可。
#include <bits/stdc++.h>using namespace std;typedef long long ll;ll g[25][25];int n;ll ans;ll dp[21][6666];ll way[6666];int main(){ while(scanf("%d",&n)!=EOF) { for(int i=0;i<n;++i) { for(int j=0;j<n;++j) { scanf("%I64d",&g[i][j]); } } memset(dp,0,sizeof(dp)); int cnt=0; ans=0; for(int i=0;i<(1<<n);++i) { if(i&(i<<1) || i&(i>>1)) continue; way[cnt]=i; for(int j=0;j<n;++j) { if((i>>j)&1) dp[0][cnt] += g[0][j]; } ans=max(ans,dp[0][cnt]); cnt++; } for(int i=1;i<n;++i) { for(int j=0;j<cnt;++j) { ll ma=0; for(int k=0;k<cnt;++k) { if(way[k] & way[j]) continue; ma=max(ma,dp[i-1][k]); } for(int k=0;k<n;++k) { if((way[j]>>k)&1) { ma+=g[i][k]; } } dp[i][j]=ma; ans=max(ans,ma); } } printf("%I64d\n",ans); } return 0;}
HDU 2167
做法:和上一题一样,只是在枚举上一行的时候多了两种状态(因为选了中间点,周围八个点都不可选)
CF 757D
做法:dp[I][J],I是位数,J是状态数(划出过的数) ,每次向后枚举做dp即可
优化:因为一共有八十个数字(2进制)且答案要连续,所以 最大连续数位为20 (重要减枝)!!
#include <bits/stdc++.h>using namespace std;typedef long long ll;const int mod=1e9+7;const int maxn=1<<20;int a[105];int dp[105][maxn+5];int main(){ int n; scanf("%d",&n); for(int i=0;i<n;++i) { char c; scanf(" %c",&c); a[i] = c-'0'; } for(int i=0;i<n;++i) { dp[i][0]=1; for(int j=0;j<(1<<20);++j) { if(!dp[i][j]) continue; int temp=0; for(int k=i;k<n;++k) { temp=(temp<<1)|a[k]; if(!temp) continue; if(temp > 20) break; dp[k+1][j|(1<<(temp-1))] = (dp[k+1][j|(1<<(temp-1))]+ dp[i][j])%mod; } } } int ans=0; for(int i=0;i<=n;++i) { for(int j=1;j<=20;++j) { ans = (ans + dp[i][(1<<j)-1])%mod; } } printf("%d\n",ans); return 0;}
HDU 5816
做法:状压DP ,dp[S],S为当前状态(n+m位二进制), 其前m个为 B牌的情况,后n个为A盘的情况
1.当伤害大于HP时,没必要接着往下做
2.当A-B+1<=0 没有手牌结束(免费有一张,每张A相当于加一张牌,每张B消耗一张牌)
3.转移的时候就O(n+m)转移
4.算上分子时 ,为 sum (dp[S] *(n+m-a-b)!) ,S为伤害大于hp的情况,剩余的牌可以随便抽(全排列)。
5.算下分母时,就是所有牌全排列即可
#include <bits/stdc++.h>using namespace std;typedef long long ll;int harm[22];ll fat[22];ll dp[1<<21];int n,m,hp,N;int main(){ fat[0]=1; for(int i=1;i<22;++i) fat[i] = i * fat[i-1]; int T; scanf("%d",&T); while(T--) { scanf("%d%d%d",&hp,&n,&m); N=n+m; memset(dp,0,sizeof(dp)); dp[0]=1; for(int i=0;i<m;++i) scanf("%d",&harm[i]); for(int i=0;i<(1<<N);++i) { if(dp[i]==0) continue; int na=0,nb=0,h=0; for(int j=0;j<m;++j) { if( i&(1<<j)) { nb++; h+=harm[j]; } } if(h>=hp) continue; for(int j=m;j<N;++j) { if(i&(1<<j)) na++; } if(na-nb+1<=0) continue; for(int j=0;j<N;++j) { if(i&(1<<j)) continue; dp[i|(1<<j)] += dp[i]; } } ll up=0 ,down=fat[N]; for(int i=0;i<(1<<N);++i) { if(dp[i]==0) continue; int na=0 , nb=0 ,h=0; for(int j=0;j<m;++j) { if( i &(1<<j)) h+=harm[j] ,++na; } for(int j=m;j<(n+m);++j) { if(i &(1<<j)) ++nb; } if(h>=hp) up+= fat[N-na-nb] * dp[i]; } ll g=__gcd(up,down); printf("%I64d/%I64d\n",up/g, down/g); } return 0;}
阅读全文
0 0
- 2017 暑假艾教集训 day2
- 2017 暑假艾教集训 day1
- 2017 暑假艾教集训 day3
- 2017 暑假艾教集训 day4
- 2017 暑假艾教集训 day5
- 2017 暑假艾教集训 day6
- 2017 暑假艾教集训 day7 (树链剖分模板)
- 2017 暑假艾教集训 day8 (补一道思维题,
- 2017 暑假艾教集训 day11 线段树!
- 2017暑假集训总结
- 2017暑假集训小结
- 2017暑假集训
- 2017暑假集训总结
- 2017暑假集训感悟
- 2017暑假集训总结
- 2017国庆郑州集训Day2
- 2017CSU暑假集训 Languages
- 2017暑假集训第一天
- 琐记1:字符串常量与数组的部分区别
- mysql主主配置错误:Slave_IO_Running: Connecting and Last_IO_Errno: 2003
- 达内课程-面向对象之对象创建过程和java数据传递
- 13. Roman to Integer(Java)
- 彻底弄懂二叉排序树
- 2017 暑假艾教集训 day2
- 抢答器
- ORACLE 学习之PL/SQL中DML和DDL语言使用
- 威威猫系列故事——打地鼠 HDU
- C++函数调用机制
- 正则表达式各种方法总结
- caioj1215
- Leetcode 649. Dota2 Senate Dota2议院 解题报告
- android MVP实践