【HDU】 4832 Chess 排列组合 DP

2024-09-05 15:48
文章标签 dp hdu 排列组合 chess 4832

本文主要是介绍【HDU】 4832 Chess 排列组合 DP,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Chess

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 351    Accepted Submission(s): 124



Problem Description
  小度和小良最近又迷上了下棋。棋盘一共有N行M列,我们可以把左上角的格子定为(1,1),右下角的格子定为(N,M)。在他们的规则中,“王”在棋盘上的走法遵循十字路线。也就是说,如果“王”当前在(x,y)点,小度在下一步可以移动到(x+1, y), (x-1, y), (x, y+1), (x, y-1), (x+2, y), (x-2, y), (x, y+2), (x, y-2) 这八个点中的任意一个。


  
图1 黄色部分为棋子所控制的范围

  小度觉得每次都是小良赢,没意思。为了难倒小良,他想出了这样一个问题:如果一开始“王”在(x0,y0)点,小良对“王”连续移动恰好K步,一共可以有多少种不同的移动方案?两种方案相同,当且仅当它们的K次移动全部都是一样的。也就是说,先向左再向右移动,和先向右再向左移动被认为是不同的方案。
  小良被难倒了。你能写程序解决这个问题吗?

 
 
Input
输入包括多组数据。输入数据的第一行是一个整数T(T≤10),表示测试数据的组数。
每组测试数据只包括一行,为五个整数N,M,K,x0,y0。(1≤N,M,K≤1000,1≤x0≤N,1≤y0≤M)

 
 
Output
对于第k组数据,第一行输出Case #k:,第二行输出所求的方案数。由于答案可能非常大,你只需要输出结果对9999991取模之后的值即可。
 
 
Sample Input
22 2 1 1 12 2 2 1 1
 
 
Sample Output
Case #1:2Case #2:4
 
 
Source
2014年百度之星程序设计大赛 - 初赛(第二轮)
题目分析:
最朴素的思想是每个点不断向旁边扩散,每个点第k次的方案数为sum(所有能到这个点的第(k-1)次所在的点的方案数之和),最终答案就是第k次所有点的方案数之和,复杂度大约是O(k*n*m),系数8,所以超时是定定的。
那么暴力不行我们应该怎么办?可以将横着走和竖着走拆开来考虑,因为这是互不影响的。设起点为(x0, y0),row[k][i]为第k步从起点走到纵坐标为 i 的方案数,col[k][i]为第k步从起点走到横坐标为 i 的方案数那么从起点(x0,y0)到(x,y)走k步的方案数即sum(col[k - d][x] * row[d][y])(d <— 0~k)。将所有横着走d步的方案累加得到cnt[0][d],所有竖着走d步的方案累加得到cnt[1][d],由排列组合可知,从横着走选d步,从竖着走选k - d步的组合数为C(k,d)。那么答案就是sum(C(k,d))(d <— 0~k)。算法的时间复杂度大约为O(n * m),十分优秀了~。

由于状态只与前一次有关,所以用了滚动数组优化。


代码如下:


#include <stdio.h>
#include <string.h>
#define MS0(X) memset(X, 0, sizeof(X))
#define REP(i, a, b) for(int i = a; i <= b; ++i)
typedef long long ll;
const int O = 1005;
const int mod = 9999991;
int col[2][O], row[2][O], cnt[2][O], C[O][O], cur;
int n, m, k, x, y, t, cas;
void work(){scanf("%d%d%d%d%d", &n, &m, &k, &x, &y);MS0(col); MS0(row); MS0(cnt);cur = 0;col[0][y] = row[0][x] = cnt[0][0] = cnt[1][0] = 1;REP(i, 1, k){cur ^= 1;MS0(col[cur]); MS0(row[cur]);REP(j, 1, m){if(j - 2 >= 1) col[cur][j] += col[cur ^ 1][j - 2];if(j - 1 >= 1) col[cur][j] += col[cur ^ 1][j - 1];if(j + 1 <= m) col[cur][j] += col[cur ^ 1][j + 1];if(j + 2 <= m) col[cur][j] += col[cur ^ 1][j + 2];col[cur][j] %= mod;cnt[0][i] = (cnt[0][i] + col[cur][j]) % mod;}REP(j, 1, n){if(j - 2 >= 1) row[cur][j] += row[cur ^ 1][j - 2];if(j - 1 >= 1) row[cur][j] += row[cur ^ 1][j - 1];if(j + 1 <= n) row[cur][j] += row[cur ^ 1][j + 1];if(j + 2 <= n) row[cur][j] += row[cur ^ 1][j + 2];row[cur][j] %= mod;cnt[1][i] = (cnt[1][i] + row[cur][j]) % mod;}}ll ans = 0;REP(i, 0, k){ans = (ans + (((ll) cnt[0][i] * cnt[1][k - i]) % mod) * C[k][i]) % mod;}printf("%I64d\n", ans);
}
int main(){REP(i, 0, O - 1) C[i][0] = 1;REP(i, 1, O - 1) REP(j, 1, i) C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % mod;for(scanf("%d", &t), cas = 1; cas <= t; ++cas){printf("Case #%d:\n", cas);work();}return 0;
}


 

这篇关于【HDU】 4832 Chess 排列组合 DP的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1139392

相关文章

hdu4826(三维DP)

这是一个百度之星的资格赛第四题 题目链接:http://acm.hdu.edu.cn/contests/contest_showproblem.php?pid=1004&cid=500 题意:从左上角的点到右上角的点,每个点只能走一遍,走的方向有三个:向上,向下,向右,求最大值。 咋一看像搜索题,先暴搜,TLE,然后剪枝,还是TLE.然后我就改方法,用DP来做,这题和普通dp相比,多个个向上

hdu1011(背包树形DP)

没有完全理解这题, m个人,攻打一个map,map的入口是1,在攻打某个结点之前要先攻打其他一个结点 dp[i][j]表示m个人攻打以第i个结点为根节点的子树得到的最优解 状态转移dp[i][ j ] = max(dp[i][j], dp[i][k]+dp[t][j-k]),其中t是i结点的子节点 代码如下: #include<iostream>#include<algorithm

hdu4865(概率DP)

题意:已知前一天和今天的天气概率,某天的天气概率和叶子的潮湿程度的概率,n天叶子的湿度,求n天最有可能的天气情况。 思路:概率DP,dp[i][j]表示第i天天气为j的概率,状态转移如下:dp[i][j] = max(dp[i][j, dp[i-1][k]*table2[k][j]*table1[j][col] )  代码如下: #include <stdio.h>#include

usaco 1.3 Mixing Milk (结构体排序 qsort) and hdu 2020(sort)

到了这题学会了结构体排序 于是回去修改了 1.2 milking cows 的算法~ 结构体排序核心: 1.结构体定义 struct Milk{int price;int milks;}milk[5000]; 2.自定义的比较函数,若返回值为正,qsort 函数判定a>b ;为负,a<b;为0,a==b; int milkcmp(const void *va,c

usaco 1.1 Broken Necklace(DP)

直接上代码 接触的第一道dp ps.大概的思路就是 先从左往右用一个数组在每个点记下蓝或黑的个数 再从右到左算一遍 最后取出最大的即可 核心语句在于: 如果 str[i] = 'r'  ,   rl[i]=rl[i-1]+1, bl[i]=0 如果 str[i] = 'b' ,  bl[i]=bl[i-1]+1, rl[i]=0 如果 str[i] = 'w',  bl[i]=b

poj 3974 and hdu 3068 最长回文串的O(n)解法(Manacher算法)

求一段字符串中的最长回文串。 因为数据量比较大,用原来的O(n^2)会爆。 小白上的O(n^2)解法代码:TLE啦~ #include<stdio.h>#include<string.h>const int Maxn = 1000000;char s[Maxn];int main(){char e[] = {"END"};while(scanf("%s", s) != EO

hdu 2093 考试排名(sscanf)

模拟题。 直接从教程里拉解析。 因为表格里的数据格式不统一。有时候有"()",有时候又没有。而它也不会给我们提示。 这种情况下,就只能它它们统一看作字符串来处理了。现在就请出我们的主角sscanf()! sscanf 语法: #include int sscanf( const char *buffer, const char *format, ... ); 函数sscanf()和

hdu 2602 and poj 3624(01背包)

01背包的模板题。 hdu2602代码: #include<stdio.h>#include<string.h>const int MaxN = 1001;int max(int a, int b){return a > b ? a : b;}int w[MaxN];int v[MaxN];int dp[MaxN];int main(){int T;int N, V;s

hdu 1754 I Hate It(线段树,单点更新,区间最值)

题意是求一个线段中的最大数。 线段树的模板题,试用了一下交大的模板。效率有点略低。 代码: #include <stdio.h>#include <string.h>#define TREE_SIZE (1 << (20))//const int TREE_SIZE = 200000 + 10;int max(int a, int b){return a > b ? a :

hdu 1166 敌兵布阵(树状数组 or 线段树)

题意是求一个线段的和,在线段上可以进行加减的修改。 树状数组的模板题。 代码: #include <stdio.h>#include <string.h>const int maxn = 50000 + 1;int c[maxn];int n;int lowbit(int x){return x & -x;}void add(int x, int num){while