HDU 5727 Necklace--二分图匹配HK算法

本文探讨了一种通过枚举和图论解决珠子配对问题的算法,旨在寻找最佳方式减少阳珠因与阴珠相邻而变暗的情况。通过使用next_permutation函数和匈牙利算法,实现了对珠子排列的最优解求解。

题意

给出N个阴珠和N个阳珠串成一串,分为阴阳珠,给出m组阴阳珠编号,这些阳珠和阴珠在一块会使得阳珠变暗,求合理的方式使得阳珠暗淡数最小,输出最小值。

思路

首先枚举阴珠相对位置,即固定一个珠的相对位置,利用next_permulation函数讨论其他珠子的相对位置。

next_permutation(yin+2,yin+n+1),yin数组若为1 2 3  那么yin数组在函数中只会变为 1 2 3、1 3 2,不用有其他变化,因为这里只需要考虑他们的相对位置,其他排列和他们是等价的。  

枚举完阴珠之后,会产生N个间隙,然后若阳珠j在间隙i里面不会变暗淡,那么连一条边。求出不会变暗淡的最大值,用n减去,就是会变暗淡的最小值。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define maxn 200+66
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define dep(i,a,b) for(int i=a;i>=b;i--)
#define mod 1000000007
#define INF 0x3f3f3f3f


struct node
{
    int to;
    int nxt;
} e[maxn*maxn];
struct Two
{
    int head[maxn*2];
    int color[maxn];
    int dep[maxn];
    int dx[maxn];
    int dy[maxn];
    int mx[maxn];
    int my[maxn];
    int n,m,cnt;
    void init(int nn)
    {
        cnt=0;
        n=nn;
        memset(head,-1,sizeof(head));
    }
    void add_edge(int u,int v)
    {
        e[cnt].to=v;
        e[cnt].nxt=head[u];
        head[u]=cnt++;
    }
    int bfs()
    {
        int flag=0;
        queue<int>q;
        for(int i=0; i<=n+1; i++)
        {
            dx[i]=dy[i]=-1;
        }
        for(int i=0; i<n; i++)
            if(mx[i]==-1)
                q.push(i);
        while(!q.empty())
        {
            int u=q.front();
            q.pop();
            for(int k=head[u]; k!=-1; k=e[k].nxt)
            {
                int v=e[k].to;
                if(dy[v]==-1)
                {
                    dy[v]=dx[u]+1;
                    if(my[v]==-1)
                        flag=1;
                    else
                    {
                        dx[my[v]]=dy[v]+1;
                        q.push(my[v]);
                    }
                }
            }
        }
        return flag;
    }
    bool dfs(int u)
    {
        for(int k=head[u]; k!=-1; k=e[k].nxt)
        {
            int v=e[k].to;
            if(dy[v]==dx[u]+1)
            {
                dy[v]=-1;
                if(my[v]==-1||dfs(my[v]))
                {
                    my[v]=u;
                    mx[u]=v;
                    return 1;
                }
            }
        }
        return 0;
    }
    int solve()
    {
        for(int i=0; i<=n+1; i++)
        {
            mx[i]=my[i]=-1;
        }
        int ans = 0;
        while(bfs())
        {
            for(int i = 0; i < n; ++i)
                if(mx[i] == -1 && dfs(i))
                    ans++;
        }
        return ans;
    }
} D;
int a[maxn];
int flag[11][11];
int yin[11];
int main()
{
    int n,m;
    while(scanf("%d %d",&n,&m)!=EOF)
    {
        if(!n)
        {
            printf("0\n");
            continue;
        }
        D.init(n);
        rep(i,1,n)rep(j,1,n)flag[i][j]=0;
        rep(i,1,m)
        {
            int a,b;
            scanf("%d %d",&a,&b);
            flag[a][b]=1;
        }
        rep(i,1,n)yin[i]=i;
        int ans=n;
        do
        {
            //rep(i,1,n)cout<<yin[i]<<" ";
            //cout<<endl;
            D.init(n);
            rep(i,1,n)
            {
                rep(j,1,n)
                {
                    int k=(i==n?1:i+1);
                    if(!flag[j][yin[i]]&&!flag[j][yin[k]])
                    {
                        D.add_edge(j-1,i-1);
                    }
                }
            }
            ans=min(ans,n-D.solve());
        }
        while(next_permutation(yin+2,yin+n+1));
        printf("%d\n",ans);
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值