poj 1186:方程的解数
2014-09-25 00:15
204 查看
题目描述如下:
其中:x1, x2,...,xn是未知数,k1,k2,...,kn是系数,p1,p2,...pn是指数。且方程中的所有数均为整数。
假设未知数1 <= xi <= M, i=1,,,n,求这个方程的整数解的个数。
1 <= n <= 6;1 <= M <= 150。
方程的整数解的个数小于231。
★本题中,指数Pi(i=1,2,...,n)均为正整数。输入第1行包含一个整数n。第2行包含一个整数M。第3行到第n+2行,每行包含两个整数,分别表示ki和pi。两个整数之间用一个空格隔开。第3行的数据对应i=1,第n+2行的数据对应i=n。输出仅一行,包含一个整数,表示方程的整数解的个数。样例输入
样例输出
一看到题目时,除了暴力,一时也没思路,于是在网上查看了几个人的博客,总结了一下思路。
例如,有n=6,即有6个xi项需要计算,这时,可先计算前三个项的和S,再计算后三个项若后三项的和等于-S,则找到一个解。
程序里将每一个S的和保存在map容器里,这样计算后三项时查找-S时,可以更快,因为map里的key与value是通过hash匹配的。
程序里,用到了递归,例如findLeft函数,它计算前n/2项的和S,并把它保存在countMap容器里。findRight函数计算后n/2项的和,转换成-S,并查看在countMap里,是否有相等项,注意,必须使用count()函数来判断S是否在Map容器里,而不能直接使用countMap[S],因为这样会在容器中增加新项,从而导致内存占用过大。
程序的代码如下:
#include <iostream>
#include <map>
using namespace std;
int countN,n,m,mid,k[6],p[6];
map<int,int> countMap;
// 搜索前一半
void findLeft(int xi, int temps){
if (mid == xi){
++countMap[temps];
return;
}
int t;
for (int i = 1; i <= m; ++i){
t = k[xi]; // xi的系数
if (t != 0 && i != 1) // 系数为0或xi=1时,则不用计算次数
for (int j = 0; j < p[xi]; ++j) // 计算xi的次方
t *= i;
findLeft(xi + 1, temps + t); // 计算x[i+1],即下一个项
}
}
// 搜索另一半,并将结果返回至列表
void findRight(int xi, int temps){
if (xi == n){
temps = -temps;
if (countMap.count(temps))
countN += countMap[temps];
return;
}
int t;
for (int i = 1; i <= m; ++i){
t = k[xi]; // xi的系数
if (t != 0 && i != 1) // 系数为0或xi=1时,则不用计算次数
for (int j = 0; j < p[xi]; ++j) // 计算xi的次方
t *= i;
findRight(xi + 1, temps + t); // 计算x[i+1],即下一个项
}
}
int main()
{
cin >> n >> m;
mid = n / 2;
for (int i = 0; i < n; ++i)
cin >> k[i] >> p[i];
findLeft(0,0);
findRight(mid, 0);
cout << countN <<endl;
}
1186:方程的解数
总时间限制: 15000ms 内存限制: 128000kB 描述已知一个n元高次方程:其中:x1, x2,...,xn是未知数,k1,k2,...,kn是系数,p1,p2,...pn是指数。且方程中的所有数均为整数。
假设未知数1 <= xi <= M, i=1,,,n,求这个方程的整数解的个数。
1 <= n <= 6;1 <= M <= 150。
方程的整数解的个数小于231。
★本题中,指数Pi(i=1,2,...,n)均为正整数。输入第1行包含一个整数n。第2行包含一个整数M。第3行到第n+2行,每行包含两个整数,分别表示ki和pi。两个整数之间用一个空格隔开。第3行的数据对应i=1,第n+2行的数据对应i=n。输出仅一行,包含一个整数,表示方程的整数解的个数。样例输入
3 150 1 2 -1 2 1 2
样例输出
178
一看到题目时,除了暴力,一时也没思路,于是在网上查看了几个人的博客,总结了一下思路。
例如,有n=6,即有6个xi项需要计算,这时,可先计算前三个项的和S,再计算后三个项若后三项的和等于-S,则找到一个解。
程序里将每一个S的和保存在map容器里,这样计算后三项时查找-S时,可以更快,因为map里的key与value是通过hash匹配的。
程序里,用到了递归,例如findLeft函数,它计算前n/2项的和S,并把它保存在countMap容器里。findRight函数计算后n/2项的和,转换成-S,并查看在countMap里,是否有相等项,注意,必须使用count()函数来判断S是否在Map容器里,而不能直接使用countMap[S],因为这样会在容器中增加新项,从而导致内存占用过大。
程序的代码如下:
#include <iostream>
#include <map>
using namespace std;
int countN,n,m,mid,k[6],p[6];
map<int,int> countMap;
// 搜索前一半
void findLeft(int xi, int temps){
if (mid == xi){
++countMap[temps];
return;
}
int t;
for (int i = 1; i <= m; ++i){
t = k[xi]; // xi的系数
if (t != 0 && i != 1) // 系数为0或xi=1时,则不用计算次数
for (int j = 0; j < p[xi]; ++j) // 计算xi的次方
t *= i;
findLeft(xi + 1, temps + t); // 计算x[i+1],即下一个项
}
}
// 搜索另一半,并将结果返回至列表
void findRight(int xi, int temps){
if (xi == n){
temps = -temps;
if (countMap.count(temps))
countN += countMap[temps];
return;
}
int t;
for (int i = 1; i <= m; ++i){
t = k[xi]; // xi的系数
if (t != 0 && i != 1) // 系数为0或xi=1时,则不用计算次数
for (int j = 0; j < p[xi]; ++j) // 计算xi的次方
t *= i;
findRight(xi + 1, temps + t); // 计算x[i+1],即下一个项
}
}
int main()
{
cin >> n >> m;
mid = n / 2;
for (int i = 0; i < n; ++i)
cin >> k[i] >> p[i];
findLeft(0,0);
findRight(mid, 0);
cout << countN <<endl;
}
相关文章推荐
- 【浅谈折半搜索】POJ1186[方程的解数]题解
- poj 1186 方程的解数 (hash+双向dfs)
- POJ1186 方程的解数
- poj 1186 poj 1840 方程的解数 hash+枚举 (n/2)
- POJ 1186 方程的解数
- POJ 1186 方程的解数 [解题报告] Java
- poj 1186 方程的解数(HASH,DFS)
- poj 1186 方程的解数【折半dfs+hash】
- poj 1186 方程的解数
- poj1186——方程的解数
- POJ 1186 方程的解数 中文
- poj 1186解方程(为什么双搜+hash)
- POJ 1186 方程的解数
- 【暴力搜索】[POJ 1186]方程的解数
- poj 1186 方程的解数 折半枚举+hash
- POJ 1186 方程的解数
- poj 1186 方程的解数(线性探测再哈希)
- 数论基础1012 POJ 1061 模线性方程
- poj_2115 C Looooops(模线性方程+扩展欧几里得)
- POJ2115——C Looooops(扩展欧几里德+求解模线性方程)