您的位置:首页 > 其它

[二分图最大匹配] number 数论 + 匈牙利算法

2017-04-05 15:18 267 查看

大家都很强, 可预置与之共勉。

一天,jyb 去视察他的军队。军队中的每名士兵都有一个编号,从1 开始编号,现在jyb 从抽出了一些编号连续的士兵,想让它们排成1 列,排队的规则是这样的:对于第i 名士兵,他的编号必须是i 的倍数。现在jyb 想知道是否能成功排队。

Input

第1 行,1 个整数T, 表示数据组数,对于每组数据:

第1 行,2 个整数n; s,n 表示选中的士兵数,编号是s + 1; s + 2; s + 3; ……; s + n

Output

对于每组数据,如果能成功排队,输出Yes;不能,输出No。

Sample

Input

2

5 14

4 11

Sample

output

No

Yes

首先,如果S小于N,那么S+1,S+2…N这些数直接放在S+1,S+2…N的位置上(如果其他数x放在这些位置上面,这些数不放在对应位置,那么x一定能放在这些数放的位置,所以直接交换即可)所以可以直接将S和N调换,缩小N。接着看N个连续的数,如果这里面有两个素数,则肯定无解,而在1e9的范围内,素数间隔最大是低于600的,我们就可以通过二分图匹配(s+i与其因数建边)求出最大匹配,若最大匹配为N,则为Yes。实际上,能满足的N其实最大为30多。

#include "ctime"
#include "cctype"
#include "cstdio"
#include "cstdlib"
#include "cstring"

#define max(a, b)  ((a) > (b) ? (a) : (b))
#define swap(a, b) { a ^= b, b ^= a, a ^= b; }
#define rep(i, m, n)  for(register int i = (m); i <= (n); ++i)

template <class T>
inline bool readIn(T &x)  {
T opt = 1;
static char ch;
while(!isdigit(ch = (char) getchar()) && (ch ^ -1) && (ch ^ 45));
if(ch == -1)  return false;
if(ch == 45)  opt = -1, ch = (char) getchar();
for(x = -48 + ch; isdigit(ch = (char) getchar()); x = (x << 1) + (x << 3) + ch - 48);
x *= opt; ungetc(ch, stdin);
return true;
}

int T, n, s, ans, match[605];
bool link[605][605], vis[605];

bool find(int x)  {
if( !x )  return false;
rep(i, 1, n)
if( !vis[i] && link[i][x] )  {
vis[i] = true;
if( !match[i] || find(match[i]) )  {
match[i] = x;
return true;
}
}
return false;
}

int main()  {
freopen("number.in", "r", stdin);
freopen("number.out", "w", stdout);
for(readIn(T); T; --T)  {
readIn(n);readIn(s);
if(n > s) swap(n, s);
if(n > 600)  { puts("No"); continue; }
memset(link, false, sizeof(link));
rep(i, 1, n)  rep(j, 1, n)  if(!((i + s) % j))  link[i][j] = true;
memset(match, 0, sizeof (int) * (n + 1));
ans = 0;
rep(i, 1, n)  {
memset(vis, 0, sizeof (int) * (n + 1));
if(find(i))  ++ans;
}
(ans ^ n) ? puts("No") : puts("Yes");
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: