标签:hellip printf ble end out 核电站 连续 scan 基础上
一个核电站有N个放核物质的坑,坑排列在一条直线上。如果连续M个坑中放入核物质,则会发生爆炸,于是,在某些坑中可能不放核物质。
任务:对于给定的N和M,求不发生爆炸的放置核物质的方案总数
只一行,两个正整数N,M( 1 < N < 50,2 ≤ M ≤ 5 )
一个正整数S,表示方案总数。
4 3
13
1 #include<iostream> 2 #include<cstring> 3 using namespace std; 4 int n, m; 5 long long d[51][6]; 6 int main(){ 7 cin>>n>>m; 8 //d(i,j)表示从1放到第i个坑,且最后i-j+1到i个坑连续放了j个炸弹的方案数 9 //最后结果是d[n][0]+……+d[n][m-1] 10 d[1][0] = 1; d[1][1] = 1; 11 for(int i = 2; i <= n; i++){ 12 for(int j = 0; j < m; j++){ 13 if(j) d[i][j] = d[i-1][j-1]; 14 else{ 15 for(int k = 0; k < m; k++) 16 d[i][j] += d[i-1][k]; 17 } 18 } 19 } 20 long long ans = 0; 21 for(int i = 0; i < m; i++) 22 ans+=d[n][i]; 23 cout<<ans<<endl; 24 return 0; 25 }
备注:这道题还挺有意思的!这个思路也基本算是自己想出来了,包括的状态的定义和边界条件、最终解!但还是差了一点,没能坚持想下去,没能想到分j=0和j≠0两种情况来考虑!
我的思考过程是这样的:很容易想到,用d[i]来表示考虑前i个坑放置炸弹的方案数,但发现仅凭这个状态没有办法转移,因为还有不能连续放m个的要求。比如说考虑d[i+1]的时候,你也不知道前i个是咋放的,因此也就不能确定第i+1个坑是否能放炸弹。
然后我就想到,再加一个维度来记录,最后几个坑位连续放了j个炸弹这种情况,也就是说
d(i,j)表示从1放到第i个坑,且最后i-j+1到i个坑连续放了j个炸弹的方案数
这样我就可以知道第i个坑能不能放炸弹了!关键在于转移过程,我没能想到j分为=0和>0两种情况,关键还是对自己的思考不自信。实际上,如果j>0的话,那就要求是在d[i][j-1]的基础上放,而且第i个坑一定要放炸弹,这样才是连续放了j个,因此d[i][j]=d[i-1][j-1],那么对于=0的情况才是关键,=0的话就相当于第i个坑一定不放炸弹,那么前面就无所谓了,所以是d[i-1][k],k从0到m-1的加总。
注意答案和数组类型都要是long long!!
一维利用容斥原理也是可以解的!关键就在于i的分类讨论。思路如下:
1 #include<cstdio> 2 long long dp[55]; 3 int main() 4 { 5 int n,m,i; 6 scanf("%d%d",&n,&m); 7 dp[0]=1; 8 for (i=1;i<=n;i++) 9 if (i==m) dp[i]=dp[i-1]*2-1; //减掉都放。 10 else 11 if (i<m) dp[i]=dp[i-1]*2; //随便放不会炸。 12 else dp[i]=dp[i-1]*2-dp[i-m-1]; 13 /*后m个固定放时前面的有dp[i-m]种放法,这些放法中都不可取。 14 但是这些放法中包含了第(i-m)放与不放两种可能,第(i-m)放的可能在(i-1)中就已排除,所以只需再排除不放的情况,即dp[i-m-1]。*/ 15 printf("%lld",dp[n]); 16 return 0; 17 }
标签:hellip printf ble end out 核电站 连续 scan 基础上
原文地址:https://www.cnblogs.com/fangziyuan/p/13124524.html