怎么判断一个二元一次方程有正整数解?

Peanuts2010 2013-12-30 05:18:13
例如: aX + bY = c( a, b, c 都大于零 )
怎么判断该方程是否有正整数解?(注意是正整数解)
...全文
1608 28 打赏 收藏 转发到动态 举报
写回复
用AI写文章
28 条回复
切换为时间正序
请发表友善的回复…
发表回复
Peanuts2010 2014-01-02
  • 打赏
  • 举报
回复
引用 14 楼 s126301 的回复:
已经回过一次了, 拓展欧几里德, 居然没理我,这次怒上代码

#include<iostream>
#include <cstring>

typedef long long lint;

lint ex_gcd(lint a, lint b, lint& x, lint& y)
{
	if(b == 0)
	{
		x = 1;
		y = 0;
		return a;
	}
	lint r = ex_gcd(b, a % b, x, y);
	lint t = x;
	x = y;
	y = t - a / b * y;
	return r;
}

bool check(lint a, lint b, lint c, lint& x, lint& y)
{
	lint r = ex_gcd(a, b, x, y);
	if(c % r)
	{
		return false;
	}
	a /= r; b /= r; c /= r;
	x *= c;
	x = ((x % b) + b ) % b;
	y = (c - a * x) / b;
	return y >= 0;
}

int main()
{
	lint a = 3000000000000L;
	lint b = 5000000000000L;
	lint c = 8000000000000L;
	lint x, y;
	if(check(a, b, c, x, y))
	{
		printf("其中一组解是:\n x = %lld, y = %lld\n", x, y);
	}
	else
	{
		printf("无解\n");
	}
	return 0;
}
辛苦你了!
Peanuts2010 2014-01-02
  • 打赏
  • 举报
回复
引用 23 楼 lyhylex 的回复:
由 x = u - vy => x = ( ui + uf ) - ( vi + vf ) * y => x = ui + uf - vi * y - vf * y 整理 => x = (ui - vi * y) + (uf - vf * y) 其中ui,vi,y为整数 保证uf - vf * y 为整数就行了
谢谢你!
lyhylex 2014-01-01
  • 打赏
  • 举报
回复
/**
	*judge if linear equations has positive integer solutions
	*vs 2012
	*c++11
	*/

#include <iostream>
using namespace std;

int main()
{
	//TODO :以下未考虑除数为0

	double a=0,b=0,c=0;
	cout<<"Enter a,b,c:"<<endl;
	cin>>a>>b>>c;

	bool swapped=a>b;
	if(swapped)swap(a,b);

	double u,v;
	u=c/a;
	v=b/a;

	double uf=u-static_cast<int>(u);
	double vf=v-static_cast<int>(v);

	const double epsilon=(numeric_limits<double>::epsilon());
	int upb=static_cast<int>(c/b);
	int less=-1;
	for (int i = 1; i <= upb; i++)
	{
		double x=u-v*i;
		double xx=floor(x+.5);
		if(fabs(x-xx)<=epsilon)
		{
			if(swapped)
				cout<<"A sultion : "<<i<<" ,  "<<static_cast<int>(x)<<endl;
			else
				cout<<"A sultion : "<<static_cast<int>(x)<<" ,  "<<i<<endl;
			break;
		}
	}

	system("pause");
}
有点退化的味道
cheney1227 2014-01-01
  • 打赏
  • 举报
回复
首先判断有没有解。然后计算
zhcosin 2014-01-01
  • 打赏
  • 举报
回复
这个方程有解的充分必要条件是 a 与 b 的最大公约数能够整除 c,这是数论中的一个定理。
Peanuts2010 2013-12-31
  • 打赏
  • 举报
回复
引用 14 楼 s126301 的回复:
已经回过一次了, 拓展欧几里德, 居然没理我,这次怒上代码

#include<iostream>
#include <cstring>

typedef long long lint;

lint ex_gcd(lint a, lint b, lint& x, lint& y)
{
	if(b == 0)
	{
		x = 1;
		y = 0;
		return a;
	}
	lint r = ex_gcd(b, a % b, x, y);
	lint t = x;
	x = y;
	y = t - a / b * y;
	return r;
}

bool check(lint a, lint b, lint c, lint& x, lint& y)
{
	lint r = ex_gcd(a, b, x, y);
	if(c % r)
	{
		return false;
	}
	a /= r; b /= r; c /= r;
	x *= c;
	x = ((x % b) + b ) % b;
	y = (c - a * x) / b;
	return y >= 0;
}

int main()
{
	lint a = 3000000000000L;
	lint b = 5000000000000L;
	lint c = 8000000000000L;
	lint x, y;
	if(check(a, b, c, x, y))
	{
		printf("其中一组解是:\n x = %lld, y = %lld\n", x, y);
	}
	else
	{
		printf("无解\n");
	}
	return 0;
}
哈哈 别着急嘛,刚从球场回来,才看到你的方法,等我吃完饭,认真学习下!
s126301 2013-12-31
  • 打赏
  • 举报
回复
已经回过一次了, 拓展欧几里德, 居然没理我,这次怒上代码

#include<iostream>
#include <cstring>

typedef long long lint;

lint ex_gcd(lint a, lint b, lint& x, lint& y)
{
	if(b == 0)
	{
		x = 1;
		y = 0;
		return a;
	}
	lint r = ex_gcd(b, a % b, x, y);
	lint t = x;
	x = y;
	y = t - a / b * y;
	return r;
}

bool check(lint a, lint b, lint c, lint& x, lint& y)
{
	lint r = ex_gcd(a, b, x, y);
	if(c % r)
	{
		return false;
	}
	a /= r; b /= r; c /= r;
	x *= c;
	x = ((x % b) + b ) % b;
	y = (c - a * x) / b;
	return y >= 0;
}

int main()
{
	lint a = 3000000000000L;
	lint b = 5000000000000L;
	lint c = 8000000000000L;
	lint x, y;
	if(check(a, b, c, x, y))
	{
		printf("其中一组解是:\n x = %lld, y = %lld\n", x, y);
	}
	else
	{
		printf("无解\n");
	}
	return 0;
}
Peanuts2010 2013-12-31
  • 打赏
  • 举报
回复
引用 3 楼 vipcxj 的回复:
[quote=引用 2 楼 Peanuts2010 的回复:] [quote=引用 楼主 Peanuts2010 的回复:] 例如: aX + bY = c( a, b, c 都大于零 ) 怎么判断该方程是否有正整数解?(注意是正整数解)
效率太低,时间达不到要求~[/quote] 那你具体说说你是从几遍历到几的?其实不需要从0遍历到c,a从1遍历到(c-b)/a,然后直接计算b或者b从1遍历到(c-a)/b,然后计算a。具体用那个,看那个便利此数更少。[/quote] 10亿 级别的
lyhylex 2013-12-31
  • 打赏
  • 举报
回复
由 x = u - vy => x = ( ui + uf ) - ( vi + vf ) * y => x = ui + uf - vi * y - vf * y 整理 => x = (ui - vi * y) + (uf - vf * y) 其中ui,vi,y为整数 保证uf - vf * y 为整数就行了
lyhylex 2013-12-31
  • 打赏
  • 举报
回复
x = u - vy x为整数,就是小数为零 u有尾数 只要v的尾数乘以整数y 得到与u的尾数相等 一减 尾数消除 得到的x即为整数
Peanuts2010 2013-12-31
  • 打赏
  • 举报
回复
是我编译器太老,在long long上出了点问题,换个就好了!等我再跟lyhylex同学讨论下就结贴给分@_@
引用 17 楼 s126301 的回复:
你确定没有输入错误? [quote=引用 16 楼 Peanuts2010 的回复:] [quote=引用 14 楼 s126301 的回复:] 已经回过一次了, 拓展欧几里德, 居然没理我,这次怒上代码

#include<iostream>
#include <cstring>

typedef long long lint;

lint ex_gcd(lint a, lint b, lint& x, lint& y)
{
	if(b == 0)
	{
		x = 1;
		y = 0;
		return a;
	}
	lint r = ex_gcd(b, a % b, x, y);
	lint t = x;
	x = y;
	y = t - a / b * y;
	return r;
}

bool check(lint a, lint b, lint c, lint& x, lint& y)
{
	lint r = ex_gcd(a, b, x, y);
	if(c % r)
	{
		return false;
	}
	a /= r; b /= r; c /= r;
	x *= c;
	x = ((x % b) + b ) % b;
	y = (c - a * x) / b;
	return y >= 0;
}

int main()
{
	lint a = 3000000000000L;
	lint b = 5000000000000L;
	lint c = 8000000000000L;
	lint x, y;
	if(check(a, b, c, x, y))
	{
		printf("其中一组解是:\n x = %lld, y = %lld\n", x, y);
	}
	else
	{
		printf("无解\n");
	}
	return 0;
}
同学,你用几个小点的整数测试下,比如 a = 2, b = 4, c = 8 ,你的程序得到结果如图所示: [/quote][/quote]
Peanuts2010 2013-12-31
  • 打赏
  • 举报
回复
引用 18 楼 lyhylex 的回复:
这更像一个数学问题 楼主给出的问题没有假定a,b,c是整数 a,b,c是实数的话gcd就不行了 由 ax + by = c => ax = c - by => x = (c/a) - (b/a)y 得到这个方程 用 u ,v 替换 (c/a) ,(b/a) 得: x = u - vy 假设 u,v 写成 “整数i.小数f”的形式 u = ui + uf (ui∈Z*,uf∈[0,1))) v = vi + vf (vi∈Z*,vf∈[0,1))) 问题要求 x,y∈Z* 要方程成立 令 t = vf * y t = ti + tf 显然有: tf 等于 uf 的整数倍 或 uf 等于 tf 的整数倍 即 tf/uf ∈ Z* 或 uf/tf ∈ Z* 因此,判断u,v的尾数即可
你好!我有下面的地方还不懂,能再讲解下吗? 先不考虑,tf, uf为零的情况 ( ui,uf,vi,vf,ti,tf跟您上边同义) 那么由 x = u - vy => x = ( ui + uf ) - ( vi + vf ) * y => x = ( ui + uf ) - vi*y - t => x = ( ui + uf ) - vi*y - ti - tf 根据您的结论,假定:uf = k * tf ( 其中k为正整数 ) => x = ( ui + k * tf ) - vi*y - ti - tf => x = ui - vi*y - ti + ( k - 1 )*tf 这里 怎么能判断 方程有正整数解呢? 或者为什么只要“ tf/uf ∈ Z* 或 uf/tf ∈ Z* ”方程就一定有正整数解呢?
Peanuts2010 2013-12-31
  • 打赏
  • 举报
回复
引用 11 楼 s126301 的回复:
拓展欧几里德, c % gcd(a,b) == 0, 必定有整数解(这里的整数可能是负数) 算法我简单说一下, 具体的可以自己百度 or google 对于 ax + by = gcd(a, b), 由于 gcd(a,b) = gcd(b, a % b) = ... 所以 ax1 + by1 = gcd(a,b) = bx2 + a % b y2 = .... = 1xn + 0yn = gcd(a,b) 至此可以求出xn, 然后反推回去, 就可以得到x1 和 y1 (程序一般直接用递归执行) 于是得到ax1 + by1 = gcd(a,b),那如何得到 ax + by = c的解呢 ax1 + by1 = gcd(a,b) -> a(x1 * c/gcd(a,b)) + b(y1 * c/gcd(a,b)) = c 于是可以求出, 一组 x = x1 * c/gcd(a,b), y = y1 * c/gcd(a,b) 然后你要判断整数解的话, 也是简单, 如果(x,y)是一组解, (x + b/gcd(a,b), y - a/gcd(a,b))也是一组解 (x - b/gcd(a,b), y + a / gcd(a,b))也是一组解 我们可以先求出x是正整数的一组解, 用取模既可 x = (x % b/gcd(a,b) + b/gcd(a,b)) % b/gcd(a,b) //这里保证x >= 0 y = (c - ax) / b, 这样的x已经是最接近0的数,于是不能在减少了 所以 如果y < 0, 那么无正整数解 如果y > 0有正整数解.
恩,在a,b,c全为正整数的情况下,你的算法思路很给力!谢谢!
lyhylex 2013-12-31
  • 打赏
  • 举报
回复
这更像一个数学问题 楼主给出的问题没有假定a,b,c是整数 a,b,c是实数的话gcd就不行了 由 ax + by = c => ax = c - by => x = (c/a) - (b/a)y 得到这个方程 用 u ,v 替换 (c/a) ,(b/a) 得: x = u - vy 假设 u,v 写成 “整数i.小数f”的形式 u = ui + uf (ui∈Z*,uf∈[0,1))) v = vi + vf (vi∈Z*,vf∈[0,1))) 问题要求 x,y∈Z* 要方程成立 令 t = vf * y t = ti + tf 显然有: tf 等于 uf 的整数倍 或 uf 等于 tf 的整数倍 即 tf/uf ∈ Z* 或 uf/tf ∈ Z* 因此,判断u,v的尾数即可
s126301 2013-12-31
  • 打赏
  • 举报
回复
你确定没有输入错误?

引用 16 楼 Peanuts2010 的回复:
[quote=引用 14 楼 s126301 的回复:]
已经回过一次了, 拓展欧几里德, 居然没理我,这次怒上代码

#include<iostream>
#include <cstring>

typedef long long lint;

lint ex_gcd(lint a, lint b, lint& x, lint& y)
{
if(b == 0)
{
x = 1;
y = 0;
return a;
}
lint r = ex_gcd(b, a % b, x, y);
lint t = x;
x = y;
y = t - a / b * y;
return r;
}

bool check(lint a, lint b, lint c, lint& x, lint& y)
{
lint r = ex_gcd(a, b, x, y);
if(c % r)
{
return false;
}
a /= r; b /= r; c /= r;
x *= c;
x = ((x % b) + b ) % b;
y = (c - a * x) / b;
return y >= 0;
}

int main()
{
lint a = 3000000000000L;
lint b = 5000000000000L;
lint c = 8000000000000L;
lint x, y;
if(check(a, b, c, x, y))
{
printf("其中一组解是:\n x = %lld, y = %lld\n", x, y);
}
else
{
printf("无解\n");
}
return 0;
}


同学,你用几个小点的整数测试下,比如 a = 2, b = 4, c = 8 ,你的程序得到结果如图所示:
[/quote]
Peanuts2010 2013-12-31
  • 打赏
  • 举报
回复
引用 14 楼 s126301 的回复:
已经回过一次了, 拓展欧几里德, 居然没理我,这次怒上代码

#include<iostream>
#include <cstring>

typedef long long lint;

lint ex_gcd(lint a, lint b, lint& x, lint& y)
{
if(b == 0)
{
x = 1;
y = 0;
return a;
}
lint r = ex_gcd(b, a % b, x, y);
lint t = x;
x = y;
y = t - a / b * y;
return r;
}

bool check(lint a, lint b, lint c, lint& x, lint& y)
{
lint r = ex_gcd(a, b, x, y);
if(c % r)
{
return false;
}
a /= r; b /= r; c /= r;
x *= c;
x = ((x % b) + b ) % b;
y = (c - a * x) / b;
return y >= 0;
}

int main()
{
lint a = 3000000000000L;
lint b = 5000000000000L;
lint c = 8000000000000L;
lint x, y;
if(check(a, b, c, x, y))
{
printf("其中一组解是:\n x = %lld, y = %lld\n", x, y);
}
else
{
printf("无解\n");
}
return 0;
}


同学,你用几个小点的整数测试下,比如 a = 2, b = 4, c = 8 ,你的程序得到结果如图所示:
zybjtu 2013-12-30
  • 打赏
  • 举报
回复
引用 10 楼 vipcxj 的回复:
[quote=引用 9 楼 zyaiwx 的回复:] [quote=引用 7 楼 vipcxj 的回复:] [quote=引用 6 楼 zyaiwx 的回复:] 那是不是说,如果a,b定了的话,其实你可以求与x轴,y轴相交的点,比如与x轴相交的点<0,那必然没有正整数解,如果与x轴,y轴相交的点都>1,那就会有正整数解
你这个不还是枚举[/quote] 这个不是枚举。如果a,b不等于0,那么,与x轴的交点是(c/a,0),如果c/a小于1那么没正整数解,因为横轴(0,c/a)之间没有正整数了;如果c/a >= 1满足,而直线与y轴的交点是(0,c/b),如果c/b<1,那么没有正整数解,反之c/b>=1 并且c/a >= 1,则有正整数解。你问得不是有没有正整数解么?if就判断出来了,也能叫枚举?[/quote] 数学证明里证明某个命题为假有种常用的方法叫举反例,下面就是我提出的反例 a=2; b=3; c=4; c/a>1; c/b>1 2x+3y=4 你给我找个正整数解试试。其实压根不需要找什么反例,从你的条件c/b>=1 并且c/a >= 1(相当于c>=b c>=a)就能轻易看出你的命题何等地不靠谱[/quote]额,不好意思,考虑还是太浅显了
s126301 2013-12-30
  • 打赏
  • 举报
回复
拓展欧几里德, c % gcd(a,b) == 0, 必定有整数解(这里的整数可能是负数) 算法我简单说一下, 具体的可以自己百度 or google 对于 ax + by = gcd(a, b), 由于 gcd(a,b) = gcd(b, a % b) = ... 所以 ax1 + by1 = gcd(a,b) = bx2 + a % b y2 = .... = 1xn + 0yn = gcd(a,b) 至此可以求出xn, 然后反推回去, 就可以得到x1 和 y1 (程序一般直接用递归执行) 于是得到ax1 + by1 = gcd(a,b),那如何得到 ax + by = c的解呢 ax1 + by1 = gcd(a,b) -> a(x1 * c/gcd(a,b)) + b(y1 * c/gcd(a,b)) = c 于是可以求出, 一组 x = x1 * c/gcd(a,b), y = y1 * c/gcd(a,b) 然后你要判断整数解的话, 也是简单, 如果(x,y)是一组解, (x + b/gcd(a,b), y - a/gcd(a,b))也是一组解 (x - b/gcd(a,b), y + a / gcd(a,b))也是一组解 我们可以先求出x是正整数的一组解, 用取模既可 x = (x % b/gcd(a,b) + b/gcd(a,b)) % b/gcd(a,b) //这里保证x >= 0 y = (c - ax) / b, 这样的x已经是最接近0的数,于是不能在减少了 所以 如果y < 0, 那么无正整数解 如果y > 0有正整数解.
vipcxj 2013-12-30
  • 打赏
  • 举报
回复
引用 9 楼 zyaiwx 的回复:
[quote=引用 7 楼 vipcxj 的回复:] [quote=引用 6 楼 zyaiwx 的回复:] 那是不是说,如果a,b定了的话,其实你可以求与x轴,y轴相交的点,比如与x轴相交的点<0,那必然没有正整数解,如果与x轴,y轴相交的点都>1,那就会有正整数解
你这个不还是枚举[/quote] 这个不是枚举。如果a,b不等于0,那么,与x轴的交点是(c/a,0),如果c/a小于1那么没正整数解,因为横轴(0,c/a)之间没有正整数了;如果c/a >= 1满足,而直线与y轴的交点是(0,c/b),如果c/b<1,那么没有正整数解,反之c/b>=1 并且c/a >= 1,则有正整数解。你问得不是有没有正整数解么?if就判断出来了,也能叫枚举?[/quote] 数学证明里证明某个命题为假有种常用的方法叫举反例,下面就是我提出的反例 a=2; b=3; c=4; c/a>1; c/b>1 2x+3y=4 你给我找个正整数解试试。其实压根不需要找什么反例,从你的条件c/b>=1 并且c/a >= 1(相当于c>=b c>=a)就能轻易看出你的命题何等地不靠谱
zybjtu 2013-12-30
  • 打赏
  • 举报
回复
引用 7 楼 vipcxj 的回复:
[quote=引用 6 楼 zyaiwx 的回复:] 那是不是说,如果a,b定了的话,其实你可以求与x轴,y轴相交的点,比如与x轴相交的点<0,那必然没有正整数解,如果与x轴,y轴相交的点都>1,那就会有正整数解
你这个不还是枚举[/quote] 这个不是枚举。如果a,b不等于0,那么,与x轴的交点是(c/a,0),如果c/a小于1那么没正整数解,因为横轴(0,c/a)之间没有正整数了;如果c/a >= 1满足,而直线与y轴的交点是(0,c/b),如果c/b<1,那么没有正整数解,反之c/b>=1 并且c/a >= 1,则有正整数解。你问得不是有没有正整数解么?if就判断出来了,也能叫枚举?
加载更多回复(8)

64,636

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧