HDU 5727 Necklace ( 2016多校、二分图匹配 )

题目链接

题意 : 给出 2*N 颗珠子、有 N 颗是阴的、有 N 颗是阳的、现在要把阴阳珠子串成一个环状的项链、而且要求珠子的放置方式必须的阴阳相间的、然后给出你 M 个限制关系、格式为 ( A、B ) 表示如果阳性 A 珠子和阴性 B 珠子相邻的话、那么阳性珠子就会衰弱、问你在最优的情况下、最少有多少颗阳珠子是衰弱的

分析 :

看题目 N 的大小只有 9

不免让人浮想联翩、跃跃欲试枚举暴力

直接暴力还是不行的

首先先枚举阴珠子所在的位置

这个可以用 next_permutation 解决

然后对于阴珠子之间的位置、到底填哪些阳珠子进去呢?

其实可以使用二分图匹配的方式

将每个位置与放到这个位置不衰弱的阳珠子相连

最后进行二分图最大匹配、答案就是 Min( N - Match() )

即最小的 N - 最大匹配结果

在 next_permutation 的时候、由于是环状的

所以不必 next_permutation 所有的阴珠子

保持其中一个不变也可以解决此题

则枚举全排列复杂度就从 9! 优化到了 8!

#include<bits/stdc++.h>
#define LL long long
#define ULL unsigned long long

#define scl(i) scanf("%lld", &i)
#define scll(i, j) scanf("%lld %lld", &i, &j)
#define sclll(i, j, k) scanf("%lld %lld %lld", &i, &j, &k)
#define scllll(i, j, k, l) scanf("%lld %lld %lld %lld", &i, &j, &k, &l)

#define scs(i) scanf("%s", i)
#define sci(i) scanf("%d", &i)
#define scd(i) scanf("%lf", &i)
#define scIl(i) scanf("%I64d", &i)
#define scii(i, j) scanf("%d %d", &i, &j)
#define scdd(i, j) scanf("%lf %lf", &i, &j)
#define scIll(i, j) scanf("%I64d %I64d", &i, &j)
#define sciii(i, j, k) scanf("%d %d %d", &i, &j, &k)
#define scddd(i, j, k) scanf("%lf %lf %lf", &i, &j, &k)
#define scIlll(i, j, k) scanf("%I64d %I64d %I64d", &i, &j, &k)
#define sciiii(i, j, k, l) scanf("%d %d %d %d", &i, &j, &k, &l)
#define scdddd(i, j, k, l) scanf("%lf %lf %lf %lf", &i, &j, &k, &l)
#define scIllll(i, j, k, l) scanf("%I64d %I64d %I64d %I64d", &i, &j, &k, &l)

#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
#define lowbit(i) (i & (-i))
#define mem(i, j) memset(i, j, sizeof(i))

#define fir first
#define sec second
#define VI vector<int>
#define ins(i) insert(i)
#define pb(i) push_back(i)
#define pii pair<int, int>
#define VL vector<long long>
#define mk(i, j) make_pair(i, j)
#define all(i) i.begin(), i.end()
#define pll pair<long long, long long>

#define _TIME 0
#define _INPUT 0
#define _OUTPUT 0
clock_t START, END;
void __stTIME();
void __enTIME();
void __IOPUT();
using namespace std;
const int maxn = 500;
int N, M;
int arr[maxn], match[maxn];
int G[maxn][maxn];
bool used[maxn];
bool mp[maxn][maxn];

struct EDGE{ int v, nxt; }Edge[maxn << 2];
int Head[maxn], cnt;

inline void init()
{
    mem(Head, -1);
    cnt = 0;
}

inline void AddEdge(int from, int to)
{
    Edge[cnt].v = to;
    Edge[cnt].nxt = Head[from];
    Head[from] = cnt++;
}

bool DFS(int v)
{
    used[v] = true;
    for(int i=Head[v]; i!=-1; i=Edge[i].nxt){
        int Eiv = Edge[i].v;
        int w = match[Eiv];
        if(w < 0 || !used[w] && DFS(w)){
            match[v] = Eiv;
            match[Eiv] = v;
            return true;
        }
    }
    return false;
}

int GetMatch()
{
    int ret = 0;
    memset(match, -1, sizeof(match));
    for(int i=1; i<=(N<<1); i++)
        if(match[i] < 0){
            memset(used, false, sizeof(used));
            if(DFS(i))
                ret++;
        }
    return ret;
}

int main(void){__stTIME();__IOPUT();

    while(~scii(N, M)){

        if(N == 0 || M == 0){
            puts("0");
            continue;
        }

        mem(mp, false);

        for(int i=0; i<M; i++){
            int A, B;
            scii(A, B);
            mp[A][B] = true;
        }
        for(int i=1; i<=N-1; i++) arr[i] = i; arr[N] = N;

        int ans = (int)(1<<30);

        do{

            //for(int i=1; i<=N; i++) printf("%d ", arr[i]); puts("");

            init();

            for(int k=1; k<=N; k++){
                int i = k + N;
                int L = arr[k];
                int R = (k == N) ? (arr[1]) : (arr[k+1]);
                for(int j=1; j<=N; j++){
                    if(mp[j][L] || mp[j][R]) continue;
                    else{
//                        AddEdge(i, j);
                        AddEdge(j, i);
                    }
                }
            }

            ans = min(ans, N - GetMatch());

        }while(next_permutation(arr+1, arr+1+N-1));

        printf("%d\n", ans);

    }

__enTIME();return 0;}

void __stTIME()
{
    #if _TIME
        START = clock();
    #endif
}

void __enTIME()
{
    #if _TIME
        END = clock();
        cerr<<"execute time = "<<(double)(END-START)/CLOCKS_PER_SEC<<endl;
    #endif
}

void __IOPUT()
{
    #if _INPUT
        freopen("in.txt", "r", stdin);
    #endif
    #if _OUTPUT
        freopen("out.txt", "w", stdout);
    #endif
}

原文地址:https://www.cnblogs.com/Rubbishes/p/9719559.html

时间: 2024-11-13 00:10:51

HDU 5727 Necklace ( 2016多校、二分图匹配 )的相关文章

hdu 2063 过山车(二分图匹配最大匹配数模板)

过山车 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 10776    Accepted Submission(s): 4748 Problem Description RPG girls今天和大家一起去游乐场玩,终于可以坐上梦寐以求的过山车了.可是,过山车的每一排只有两个座位,而且还有条不成文的规矩,就是每个女生必须找个个男生做par

hdu 5727 Necklace 二分图匹配

题目链接 给2*n个珠子, n<=9, n个阴n个阳. 然后将它们弄成一个环, 阴阳交替.现在给你m个关系, 每个关系给出a, b. 如果阳a和阴b挨着, 那么a就会变暗. 问你最小变暗几个阳. 我们求出阴的所有全排列, 是9!, 因为形成一个环. 所以可以想象成一个珠子是固定不变的, 剩下n-1个变, 所以就是8!. 然后对于每种情况, 就是我们熟悉的二分图匹配了. 对于两个阴珠之间的空隙, 如果阳珠可以放到这里就连一条边. 然后跑匈牙利匹配就可以了. 9!过不了... #include <

HDU 5943 Kingdom of Obsession 【二分图匹配 匈牙利算法】 (2016年中国大学生程序设计竞赛(杭州))

Kingdom of Obsession Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 49    Accepted Submission(s): 14 Problem Description There is a kindom of obsession, so people in this kingdom do things very

HDU 5727 Necklace

枚举环排列+二分图匹配计算答案. 可以枚举一下yin的排列方式,因为是环,所以可以固定一个,剩下的8个进行全排列. 对于每一个全排列,会产生n个位置供yang放置,如果某位置放置某yang不会使该yang褪色,则该位置向该yang连边. 然后跑一次二分图最大匹配,即可得到在yin这样的排列方式下,最多有多少yang不会褪色,更新一下答案. #include<cstdio> #include<cstring> #include<cmath> #include<alg

hdu 5727 Necklace 阴阳珠 二分图匹配+暴力全排列

Necklace Time Limit: 3000/1500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 2462    Accepted Submission(s): 775 Problem Description SJX has 2*N magic gems. N of them have Yin energy inside while others have Yang e

HDU 5727 Necklace 二分图匈牙利最大匹配,

给你阴阳球各n个,某些阳球只要周围有一个阴球,就会变暗,问最后至少要变暗多少个. 看了题解,说是全排列阴球,因为成环,所以就能变成8!复杂度,就能跑了. 然后每种情况,如果一个阳球碰上周围两个阴球都不变暗,那么久能放在这个位置,此时的最大匹配就是这种方案,最大可以放,并且不变暗的,个数.拿n一减,完事取最小值就行.就是暴力. 完事还有一个最好用的函数next......(bulabula),直接得到全排列. #include <iostream> #include <cstdio>

HDU 5727 Necklace 二分+匹配

这是从山东大学巨巨那里学来的做法 枚举下黑色球的排列总数是8!,然后八个白球可选的位置与左右两个黑球存不存在关系建图就行 这是原话,具体一点,每次生成环排,只有互不影响的才连边 最后:注重一点,n个数环排是(n-1)! #include <stdio.h> #include <iostream> #include <algorithm> #include <string.h> #include <vector> #include <map&

Hdu 3289 Rain on your Parade (二分图匹配 Hopcroft-Karp)

题目链接: Hdu 3289 Rain on your Parade 题目描述: 有n个客人,m把雨伞,在t秒之后将会下雨,给出每个客人的坐标和每秒行走的距离,以及雨伞的位置,问t秒后最多有几个客人可以拿到雨伞? 解题思路: 数据范围太大,匈牙利算法O(n*m)果断华丽丽的TLE,请教了一下度娘,发现还有一种神算法—— Hopcroft-Karp,然后就get√新技能,一路小跑过了,有一点不明白的是hdu上竟然有人0ms过,这又是什么神姿势(吓哭!!!!!),额.........,扯远了.  H

【HDU 1150】Machine Schedule(二分图匹配)

机器的不同模式为点,对于每个job,建两条边 A机器需要的模式<->B机器需要的模式. 问题转化为最小点覆盖,然后用二分图的最小点覆盖==最大匹配,用匈牙利算法解. #include <cstdio> #include <cstring> const int N=105<<1; const int M=1001<<1; struct edge{ int to,next; }e[M]; int head[N],tot; void add(int u