备战2019蓝桥杯
2014.地宫取宝(DFS+记忆化搜索)
问题描述: X 国王有一个地宫宝库,是 n*m 个格子的矩阵。 每个格子放一件宝贝,每个宝贝贴着价值标签。 地宫的入口在左上角,出口在右下角。 小明被带到地宫的入口,国王要求他只能向右或向下行走。 走过某个格子时,如果那个格子中的宝贝价值比小明手中任意宝贝价值都大,小明就可以拿起它(当然,也可以不拿)。 当小明走到出口时,如果他手中的宝贝恰好是 k 件,则这些宝贝就可以送给小明。 请你帮小明算一算,在给定的局面下,他有多少种不同的行动方案能获得这k件宝贝。 输入格式 输入一行3个整数,用空格分开:n m k (1<=n,m<=50, 1<=k<=12) 接下来有 n 行数据,每行有 m 个整数 Ci (0<=Ci<=12)代表这个格子上的宝物的价值 输出格式 要求输出一个整数,表示正好取k个宝贝的行动方案数。该数字可能很大,输出它对 1000000007 取模的结果。 样例输入 2 2 2 1 2 2 1 样例输出 2 样例输入 2 3 2 1 2 3 2 1 5 样例输出 14
AC代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 #define ll long long 6 #define mem(a,b) memset(a,b,sizeof(a)) 7 const int MOD=1e9+7; 8 9 int n,m,k; 10 int maze[60][60]; 11 ll dp[60][60][15][15];//记忆化搜索 12 13 ll DFS(int x,int y,int curTot,int curMax) 14 { 15 //须注意的一点是curMax可能有为-1的情况,所以将所有的curMax+1 16 if(dp[x][y][curTot][curMax+1] != -1) 17 return dp[x][y][curTot][curMax+1]; 18 19 if(x == n+1 || y == m+1 || curTot > k) 20 return 0; 21 22 if(x == n && y == m) 23 { 24 if(curTot == k || (curTot == k -1 && maze[x][y] > curMax)) 25 return 1; 26 return 0; 27 } 28 ll ans=0; 29 if(maze[x][y] > curMax) 30 { 31 ans += DFS(x+1,y,curTot+1,maze[x][y]); 32 ans += DFS(x,y+1,curTot+1,maze[x][y]); 33 } 34 ans += DFS(x+1,y,curTot,curMax); 35 ans += DFS(x,y+1,curTot,curMax); 36 ans %= MOD; 37 38 dp[x][y][curTot][curMax+1]=ans; 39 return ans; 40 } 41 int main() 42 { 43 while(~scanf("%d%d%d",&n,&m,&k)) 44 { 45 for(int i=1;i <= n;++i) 46 for(int j=1;j <= m;++j) 47 scanf("%d",&maze[i][j]); 48 mem(dp,-1);//宝贝价值可能为0,所以将dp初始化为-1 49 printf("%lld\n",DFS(1,1,0,-1)); 50 } 51 return 0; 52 }
2014.蚂蚁感冒(思维题)
问题描述 长100厘米的细长直杆子上有n只蚂蚁。它们的头有的朝左,有的朝右。 每只蚂蚁都只能沿着杆子向前爬,速度是1厘米/秒。 当两只蚂蚁碰面时,它们会同时掉头往相反的方向爬行。 这些蚂蚁中,有1只蚂蚁感冒了。并且在和其它蚂蚁碰面时,会把感冒传染给碰到的蚂蚁。 请你计算,当所有蚂蚁都爬离杆子时,有多少只蚂蚁患上了感冒。 输入格式 第一行输入一个整数n (1 < n < 50), 表示蚂蚁的总数。 接着的一行是n个用空格分开的整数 Xi (-100 < Xi < 100), Xi的绝对值,表示蚂蚁离开杆子左边端点的距离。正值表示头朝右,负值表示头朝左,数据中不会出现0值,也不会出现两只蚂蚁占用同一位置。其中,第一个数据代表的蚂蚁感冒了。 输出格式 要求输出1个整数,表示最后感冒蚂蚁的数目。 样例输入 3 5 -2 8 样例输出 1 样例输入 5 -10 8 -20 12 25 样例输出 3
题解:
首先,将所有蚂蚁按在杆子上的位置从小到大排序;
从左向右依次便利每一只蚂蚁,并判断当前蚂蚁离开杆子时是否患有感冒;
AC代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 using namespace std; 6 #define mem(a,b) memset(a,b,sizeof(a)) 7 const int maxn=200; 8 9 int n; 10 struct Date 11 { 12 bool dir;//1:向右走;0:向左走 13 int pos; 14 bool isCold;//true:cold;false:no cold 15 Date(int dir=0,int pos=0,int isCold=0):dir(dir),pos(pos),isCold(isCold){} 16 }ant[maxn]; 17 18 bool cmp(Date _a,Date _b) 19 { 20 return _a.pos < _b.pos; 21 } 22 int Solve() 23 { 24 sort(ant+1,ant+n+1,cmp); 25 int index=1; 26 int ans=0; 27 while(index <= n)//从左边开始 28 { 29 if(!ant[index].dir)//左边的蚂蚁向左走,直接爬出杆子 30 { 31 ans += (ant[index].isCold ? 1:0); 32 index++; 33 } 34 else//左边的蚂蚁向右走 35 { 36 int t=index+1; 37 while(t <= n && ant[t].dir)//找到其右边的最先向左走的蚂蚁 38 t++; 39 if(t == n+1)//t == n+1,说明当前杆子上剩余的蚂蚁全部向右走,直接爬出杆子 40 { 41 for(int i=index;i < t;++i) 42 ans += ant[i].isCold; 43 break; 44 } 45 //更新[index,t-1]之间蚂蚁的isCode和dir 46 for(int i=t-1;i >= index;--i) 47 { 48 if(ant[i].isCold || ant[i+1].isCold) 49 ant[i].isCold=ant[i+1].isCold=true; 50 51 ant[i].dir=!ant[i].dir; 52 ant[i+1].dir=!ant[i+1].dir; 53 } 54 55 ans += (ant[index].isCold ? 1:0);//判断当前蚂蚁是否感冒 56 index++;//爬出杆子 57 } 58 } 59 return ans; 60 } 61 int main() 62 { 63 scanf("%d",&n); 64 for(int i=1;i <= n;++i) 65 { 66 int x; 67 scanf("%d",&x); 68 ant[i]=Date(x > 0,abs(x),i == 1); 69 } 70 printf("%d\n",Solve()); 71 72 return 0; 73 }