【二分图】number

一天,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。

in:

2
5 14
4 11

out:

No
Yes

第一眼感觉是二分图,然后瞎打了个二分图匹配的暴力上去

#include<bits/stdc++.h>
#define mem(x) memset(x,0,sizeof(x))
using namespace std;

int T,n,s,cnt;
int can[405][405];
bool vis[405];
int match[405];

inline void swap(int &a,int &b){int t=a;a=b;b=t;}

bool check(int x)
{
    if(!x) return false;
    for(register int i=1;i<=n;++i)
    {
        if(!vis[i]&&can[i][x])//未访问且可匹配
        {
            vis[i]=1;
            if(!match[i]||check(match[i]))//若没有匹配或下一个有匹配
            {
                match[i]=x;
                return true;
            } 
        }
    }
    return false;
}

template<class T> inline void read(T &re)
{
    re=0;T sign=1;char tmp;
    while((tmp=getchar())&&(tmp<'0'||tmp>'9')) if(tmp=='-') sign=-1;re=tmp-'0';
    while((tmp=getchar())&&(tmp>='0'&&tmp<='9')) re=re*10+(tmp-'0');re*=sign;
}

inline void clear()
{
    mem(can);
    mem(match);
    cnt=0;
}

int main()
{
    freopen("number.in","r",stdin);
    freopen("number.out","w",stdout);
    read(T);
    while(T--)
    {
        clear();
        read(n);read(s);

        for(register int i=1;i<=n;++i)
            for(register int j=1;j<=n;++j)
                if(!((s+i)%j)) can[i][j]=1;

        for(register int i=1;i<=n;++i)
        {
            mem(vis);
            if(check(i)) ++cnt;
        }
        printf(n==cnt?"Yes\n":"No\n");
    }
    return 0;
}

T到飞起

这是因为二分图的复杂度是O(n³),1e9的数据显然过不去,想到使用网络流

抱歉网络流也过不去,告辞

转念一想,1e9范围内,相邻质数的差不超过600

那么超过600就一定会有两个质数同时要求匹配,质数的因子只有1和本身,因此一定不匹配

if(n>600) {printf("No\n");continue;}

另外,如果n>s呢?画画图,等价于swap(n,s)

这样便达到了缩小n的目的

于是把暴力代码改改

#include<bits/stdc++.h>
#define mem(x) memset(x,0,sizeof(x))
using namespace std;

int T,n,s,cnt;
int can[405][405];
bool vis[405];
int match[405];

inline void swap(int &a,int &b){int t=a;a=b;b=t;}

bool check(int x)
{
    if(!x) return false;
    for(register int i=1;i<=n;++i)
    {
        if(!vis[i]&&can[i][x])//未访问且可匹配
        {
            vis[i]=1;
            if(!match[i]||check(match[i]))//若没有匹配或下一个有匹配
            {
                match[i]=x;
                return true;
            } 
        }
    }
    return false;
}

template<class T> inline void read(T &re)
{
    re=0;T sign=1;char tmp;
    while((tmp=getchar())&&(tmp<'0'||tmp>'9')) if(tmp=='-') sign=-1;re=tmp-'0';
    while((tmp=getchar())&&(tmp>='0'&&tmp<='9')) re=re*10+(tmp-'0');re*=sign;
}

inline void clear()
{
    mem(can);
    mem(match);
    cnt=0;
}

int main()
{
    freopen("number.in","r",stdin);
    freopen("number.out","w",stdout);
    read(T);
    while(T--)
    {
        clear();
        read(n);read(s);
        if(n>s) swap(n,s);
        if(n>400) {printf("No\n");continue;}

        for(register int i=1;i<=n;++i)
            for(register int j=1;j<=n;++j)
                if(!((s+i)%j)) can[i][j]=1;

        for(register int i=1;i<=n;++i)
        {
            mem(vis);
            if(check(i)) ++cnt;
        }
        printf(n==cnt?"Yes\n":"No\n");
    }
    return 0;
}
/*
2
5 14
4 11
 */

就可以了

(当然我考试的时候写的400上界,对拍了一下没什么问题= =,600那个数据太特殊了,而且二分图跑不过去qwq)

update:发现网络流不能交换,这样会导致边的方向改变,因此本题时限并不严谨,上限是400而不是600

猜你喜欢

转载自www.cnblogs.com/tqr06/p/10665519.html