hihocoder 1158 质数相关 (二分图最大独立集 最大流ISAP求解)

#1158 : 质数相关

时间限制:2000ms

单点时限:1000ms

内存限制:256MB

描述

两个数a和 b (a<b)被称为质数相关,是指a × p = b,这里p是一个质数。一个集合S被称为质数相关,是指S中存在两个质数相关的数,否则称S为质数无关。如{2, 8, 17}质数无关,但{2, 8, 16}, {3, 6}质数相关。现在给定一个集合S,问S的所有质数无关子集中,最大的子集的大小。

输入

第一行为一个数T,为数据组数。之后每组数据包含两行。

第一行为N,为集合S的大小。第二行为N个整数,表示集合内的数。

输出

对于每组数据输出一行,形如"Case #X: Y"。X为数据编号,从1开始,Y为最大的子集的大小。

数据范围

1 ≤ T ≤ 20

集合S内的数两两不同且范围在1到500000之间。

小数据

1 ≤ N ≤ 15

大数据

1 ≤ N ≤ 1000

样例输入

3

5

2 4 8 16 32

5

2 3 4 6 9

3

1 2 3

样例输出

Case #1: 3

Case #2: 3

Case #3: 2

题目链接:http://hihocoder.com/problemset/problem/1158

题目分析:求二分图最大独立集,点权-最大匹配(网络流最小割)=最大独立集

建图方法:把素数分解时素因子都为奇数的数作为二分图的一边,另一边为左边数字质数相关的数

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <cmath>
using namespace std;
int const MAX = 500005;
int const MAXN = 3000005;
int const INF = 0x7fffffff;
int p[MAX], a[1005];
bool prime[MAX];
int gap[MAXN], pre[MAXN], head[MAXN], d[MAXN], cur[MAXN];
int e_cnt, n;
int src, sink;

void get_prime()
{
    memset(prime, true, sizeof(prime));
    prime[1] = false;
    for(int i = 2; i <= sqrt(500000); i++)
        if(prime[i])
            for(int j = i + i; j <= 500000; j += i)
                prime[j] = 0;
}

struct EDGE
{
    int to, cap, flow, next;
}e[MAXN];

void Add_Edge(int u, int v, int cap)
{
    e[e_cnt].to = v;
    e[e_cnt].cap = cap;
    e[e_cnt].flow = 0;
    e[e_cnt].next = head[u];
    head[u] = e_cnt ++;

    e[e_cnt].to = u;
    e[e_cnt].cap = 0;
    e[e_cnt].flow = 0;
    e[e_cnt].next = head[v];
    head[v] = e_cnt ++;
}

void BFS(int t)
{
    queue <int> Q;
    memset(gap, 0, sizeof(gap));
    memset(d, -1, sizeof(d));
    d[t] = 0;
    Q.push(t);
    while(!Q.empty())
    {
        int v = Q.front();
        Q.pop();
        gap[d[v]] ++;
        for(int i = head[v]; i != -1; i = e[i].next)
        {
            int u = e[i].to;
            if(d[u] == -1)
            {
                d[u] = d[v] + 1;
                Q.push(u);
            }
        }
    }
}

int ISAP(int s, int t)
{
    BFS(t);
    int ans = 0, u = s, flow = INF;
    memcpy(cur, head, sizeof(cur));
    while(d[s] < e_cnt)
    {
        int i = cur[u];
        for(; i != - 1; i = e[i].next)
        {
            int v = e[i].to;
            if(e[i].cap > e[i].flow && d[u] == d[v] + 1)
            {
                u = v;
                pre[v] = i;
                flow = min(flow, e[i].cap - e[i].flow);
                if(u == t)
                {
                    while(u != s)
                    {
                        int j = pre[u];
                        e[j].flow += flow;
                        e[j ^ 1].flow -= flow;
                        u = e[j ^ 1].to;
                    }
                    ans += flow;
                    flow = INF;
                }
                break;
            }
        }
        if(i == -1)
        {
            if(-- gap[d[u]] == 0)
                break;
            int mi = e_cnt - 1;
            cur[u] = head[u];
            for(int j = head[u]; j != -1; j = e[j].next)
                if(e[j].cap > e[j].flow)
                    mi = min(mi, d[e[j].to]);
            d[u] = mi + 1;
            gap[d[u]] ++;
            if(u != s)
                u = e[pre[u] ^ 1].to;
        }
    }
    return ans;
}

int main()
{
    get_prime();
    p[1] = 0;
    for(int i = 1; i <= 500000; i++)
        for(int j = 1; j <= 500000 / i; j++)
            if(prime[j])
                p[i * j] = 1 - p[i];
    int T;
    scanf("%d", &T);
    for(int ca = 1; ca <= T; ca++)
    {
        e_cnt = 0;
        memset(head, -1, sizeof(head));
        printf("Case #%d: ", ca);
        scanf("%d", &n);
        for(int i = 1; i <= n; i++)
            scanf("%d", &a[i]);
        src = 0;
        sink = n + 1;
        for(int i = 1; i <= n; i++)
        {
            if(p[a[i]])
                Add_Edge(src, i, 1);
            else
                Add_Edge(i, sink, 1);
        }
        for(int i = 1; i <= n; i++)
        {
            if(p[a[i]])
            {
                for(int j = 1; j <= n; j++)
                {
                    if(!p[a[j]])
                    {
                        if(a[i] > a[j])
                        {
                            if(a[i] % a[j] == 0 && prime[a[i] / a[j]])
                                Add_Edge(i, j, 1);
                        }
                        else
                        {
                            if(a[j] % a[i] == 0 && prime[a[j] / a[i]])
                                Add_Edge(i, j, 1);
                        }
                    }
                }
            }
        }
        printf("%d\n", n - ISAP(src, sink));
    }
}
时间: 2024-10-12 07:50:53

hihocoder 1158 质数相关 (二分图最大独立集 最大流ISAP求解)的相关文章

HihoCoder 1158 : 质数相关 (最大独立集)

质数相关 时间限制:2000ms 单点时限:1000ms 内存限制:256MB 描述 两个数a和 b (a<b)被称为质数相关,是指a × p = b,这里p是一个质数.一个集合S被称为质数相关,是指S中存在两个质数相关的数,否则称S为质数无关.如{2, 8, 17}质数无关,但{2, 8, 16}, {3, 6}质数相关.现在给定一个集合S,问S的所有质数无关子集中,最大的子集的大小. 输入 第一行为一个数T,为数据组数.之后每组数据包含两行. 第一行为N,为集合S的大小.第二行为N个整数,表

[hihoCoder] #1158 : 质数相关

时间限制:2000ms 单点时限:1000ms 内存限制:256MB 描述 两个数a和 b (a<b)被称为质数相关,是指a × p = b,这里p是一个质数.一个集合S被称为质数相关,是指S中存在两个质数相关的数,否则称S为质数无关.如{2, 8, 17}质数无关,但{2, 8, 16}, {3, 6}质数相关.现在给定一个集合S,问S的所有质数无关子集中,最大的子集的大小. 输入 第一行为一个数T,为数据组数.之后每组数据包含两行. 第一行为N,为集合S的大小.第二行为N个整数,表示集合内的

hihocoder 1158 质数相关 dp

描述 两个数a和 b (a<b)被称为质数相关,是指a × p = b,这里p是一个质数.一个集合S被称为质数相关,是指S中存在两个质数相关的数,否则称S为质数无关.如{2, 8, 17}质数无关,但{2, 8, 16}, {3, 6}质数相关.现在给定一个集合S,问S的所有质数无关子集中,最大的子集的大小. 输入 第一行为一个数T,为数据组数.之后每组数据包含两行. 第一行为N,为集合S的大小.第二行为N个整数,表示集合内的数. 输出 对于每组数据输出一行,形如"Case #X: Y&q

编程之美2015初赛_质数相关(二分图)

质数相关 题意:求二分图的最大独立集(独立集就是图中任意两个顶点都不相连的顶点集合) 思路:交替染色法,两种颜色把图染色.颜色最多的即为最大独立集. #include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<queue> #include<set> #include<map&

编程之美2015 round2a c 二分图最大独立集

题目描述: 两个数a和b(a<b)被称为质数相关,是指a × p = b,这里p是一个质数.一个集合S被称为质数相关,是指S中存在两个质数相关的数,否则称S为质数无关.如{2, 8, 17}质数无关,但{2, 8, 16}, {3, 6}质数相关.现在给定一个集合S,问S的所有质数无关子集中,最大的子集的大小. 思路: 最大独立集,大致分析了一下感觉是二分图,没有详细证明,不过大数据过了,应该是对的吧,求大神证明是二分图. 1 #include <iostream> 2 #include

hiho 编程之美2015初赛第一场(质数相关-2分图匹配)

两个数a和 b (a<b)被称为质数相关,是指a × p = b,这里p是一个质数.一个集合S被称为质数相关,是指S中存在两个质数相关的数,否则称S为质数无关.如{2, 8, 17}质数无关,但{2, 8, 16}, {3, 6}质数相关.现在给定一个集合S,问S的所有质数无关子集中,最大的子集的大小. 输入 第一行为一个数T,为数据组数.之后每组数据包含两行. 第一行为N,为集合S的大小.第二行为N个整数,表示集合内的数. 输出 对于每组数据输出一行,形如"Case #X: Y"

[luoguP3355] 骑士共存问题(二分图最大独立集)

传送门 模型 二分图最大独立集,转化为二分图最大匹配,从而用最大流解决. 实现 首先把棋盘黑白染色,使相邻格子颜色不同. 把所有可用的黑色格子看做二分图X集合中顶点,可用的白色格子看做Y集合顶点. 建立附加源S汇T,从S向X集合中每个顶点连接一条容量为1的有向边,从Y集合中每个顶点向T连接一条容量为1的有向边. 从每个可用的黑色格子向骑士一步能攻击到的可用的白色格子连接一条容量为无穷大的有向边. 求出网络最大流,要求的结果就是可用格子的数量减去最大流量. 分析 用网络流的方法解决棋盘上的问题,一

2015编程之美初赛第一场 C 质数相关

 时间限制:2000ms 单点时限:1000ms 内存限制:256MB 描述 两个数a和 b (a<b)被称为质数相关,是指a × p = b,这里p是一个质数.一个集合S被称为质数相关,是指S中存在两个质数相关的数,否则称S为质数无关.如{2, 8, 17}质数无关,但{2, 8, 16}, {3, 6}质数相关.现在给定一个集合S,问S的所有质数无关子集中,最大的子集的大小. 输入 第一行为一个数T,为数据组数.之后每组数据包含两行. 第一行为N,为集合S的大小.第二行为N个整数,表示集

fzu 2039 Pets (简单二分图 + (最大流 || 二分图))

Are you interested in pets? There is a very famous pets shop in the center of the ACM city. There are totally m pets in the shop, numbered from 1 to m. One day, there are n customers in the shop, which are numbered from 1 to n. In order to sell pets