Kingdom of Obsession---hdu5943(二分匹配)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5943

题意:给你两个数n, s 然后让你判断是否存在(s+1, s+2, s+3, ... , s+n )的任意排列方式使得每个数都满足当前数num,与num所在位置 pos  形成num%pos=0;

例如 n = 4 , s = 11

num = {13, 14, 15, 12}

pos =  {1,    2,   3,    4}

每个num与之对应的pos都是num%pos = 0;的关系

分为两种情况:当s+1>n 时,我们只需看第二个数组中是否含有>=2个素数即可, 因为1只有1个;

当s+1<=n时,两个区间有重叠,我们可以忽略这些重叠部分,看两端的即可,其实就是交换一下n,s的值; 

其实就是两个数组建图,然后求最大匹配是否为1,当然n比较大,但是连续600个数中间一定包含>=2个素数,所以当n<600时可以用二分匹配来做;

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<vector>
using namespace std;
typedef long long LL;
const int oo = 0xfffffff;
const int N = 615;

int used[N], vis[N], n, s;
vector<int> G[N];

bool Find(int u)
{
    int len=G[u].size();
    for(int i=0; i<len; i++)
    {
        int v = G[u][i];
        if(!vis[v])
        {
            vis[v] = 1;
            if(!used[v] || Find(used[v]))
            {
                used[v] = u;
                return true;
            }
        }
    }
    return false;
}

int main()
{
    int T, t = 1;
    scanf("%d", &T);
    while(T --)
    {
        scanf("%d %d", &n, &s);

        if(s+1 <= n)///忽略中间重合的部分;
            swap(s, n);

        if(n > 600)///因为连续600个数中一定有>=2个素数, 1只有一个,所以结果都是No;
        {
            printf("Case #%d: No
", t++);
            continue;
        }

        for(int i=0; i<=n; i++)
            G[i].clear();

        for(int i=1; i<=n; i++)
        {
            for(int j=1; j<=n; j++)
            {
                if((s+i)%j == 0)///说明s+i是j的倍数;
                    G[i].push_back(j);
            }
        }
        memset(used, 0, sizeof(used));
        int ans = 0;
        for(int i=1; i<=n; i++)
        {
            memset(vis, 0, sizeof(vis));
            ans += Find(i);
        }
        if(ans != n)///必须要找到所有与之对应的才可以;
            printf("Case #%d: No
", t++);
        else
            printf("Case #%d: Yes
", t++);
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/zhengguiping--9876/p/6011534.html