zoukankan      html  css  js  c++  java
  • [bzoj4405][wc2016]挑战NPC

    来自FallDream的博客,未经允许,请勿转载,谢谢。


    小N最近在研究NP完全问题,小O看小N研究得热火朝天,便给他出了一道这样的题目:
    有n个球,用整数1到n编号。还有m个筐子,用整数1到m编号。
    每个筐子最多能装3个球。
    每个球只能放进特定的筐子中。具体有e个条件,第i个条件用两个整数vi和ui描述,表示编号为vi的球可以放进编号为ui的筐子中。
    每个球都必须放进一个筐子中。如果一个筐子内有不超过1个球,那么我们称这样的筐子为半空的。
    求半空的筐子最多有多少个,以及在最优方案中,每个球分别放在哪个筐子中。
    小N看到题目后瞬间没了思路,站在旁边看热闹的小I嘿嘿一笑:“水题!”
    然后三言两语道出了一个多项式算法。
    小N瞬间就惊呆了,三秒钟后他回过神来一拍桌子:
    “不对!这个问题显然是NP完全问题,你算法肯定有错!”
    小I浅笑:“所以,等我领图灵奖吧!”
    小O只会出题不会做题,所以找到了你——请你对这个问题进行探究,并写一个程序解决此题。
    T<=5  n<=300 m<=100
     
    考虑每个筐子拆成3个点,在被匹配走0/1/2/3个点的情况下能够产生的最大匹配和想要的贡献相同
    只需要在其中两个点之间连一条边就好啦
    然后带花树
    其实我是想贴个模板
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #define MN 600
    using namespace std;
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    int head[MN+5],vis[MN+5],cnt=0,n,m,Q,q[MN*MN],now=0,mark[MN+5],match[MN+5],ne[MN+5],fa[MN+5],top,tail;
    struct edge{int to,ne;}e[MN*MN+5];
    inline int getfa(int x){return !fa[x]?x:fa[x]=getfa(fa[x]);}
    inline void ins(int f,int t)
    {
        e[++cnt]=(edge){t,head[f]};head[f]=cnt;
        e[++cnt]=(edge){f,head[t]};head[t]=cnt;
    }
    
    int Lca(int x,int y)
    {
        ++now;
        for(;;swap(x,y))
            if(x!=-1)
            {
                x=getfa(x);
                if(vis[x]==now) return x;
                vis[x]=now;
                if(match[x]) x=ne[match[x]];
                else x=-1;
            }
    }
    
    void Unit(int x,int y)
    {
        x=getfa(x);y=getfa(y);
        if(x!=y) fa[x]=y;
    }
    
    void group(int a,int p)
    {
        for(;a!=p;)
        {
            int b=match[a],c=ne[b];
            if(getfa(c)!=p) ne[c]=b;
            if(mark[b]==2) mark[q[++top]=b]=1;
            if(mark[c]==2) mark[q[++top]=c]=1;
            Unit(a,b);Unit(b,c);
            a=c;
        }
    }
    
    void Solve(int x)
    {
        for(int i=1;i<=n+3*m;++i) ne[i]=fa[i]=mark[i]=vis[i]=0;
        mark[x]=1;q[top=tail=0]=x;
        for(;!match[x]&&top>=tail;++tail)
        {
            int y=q[tail];
            for(int i=head[y];i;i=e[i].ne)
            {
                int v=e[i].to;
                if(match[y]==v||mark[v]==2||getfa(y)==getfa(v)) continue;
                if(mark[v]==1)
                {
                    int lca=Lca(y,v);
                    if(getfa(y)!=lca) ne[y]=v;
                    if(getfa(v)!=lca) ne[v]=y;
                    group(y,lca);
                    group(v,lca);
                }
                else if(!match[v])
                {
                    ne[v]=y;
                    for(int u=v;u;)
                    {
                        int w=ne[u],ww=match[w];
                        match[w]=u,match[u]=w;
                        u=ww;
                    }
                    return;
                }
                else
                {
                    ne[v]=y;
                    mark[q[++top]=match[v]]=1;
                    mark[v]=2;
                }
            }
        }
    }
    
    int main()
    {
        for(int T=read();T;--T)
        {
            memset(head,0,sizeof(head));
            memset(match,0,sizeof(match));cnt=0;
            n=read();m=read();Q=read();
            for(int i=1;i<=Q;++i)
            {
                int x=read(),y=read();
                ins(x,y+n);ins(x,y+n+m);ins(x,y+n+m+m);
            }
            for(int i=1;i<=m;++i) ins(i+n,i+n+m);
            for(int i=1;i<=n+3*m;++i)
                if(!match[i]) Solve(i);
            int ans=0;
            for(int i=1;i<=n+3*m;++i) if(match[i]) ++ans;
            printf("%d
    ",(ans>>1)-n); 
        }
        return 0;
    }
     
     
  • 相关阅读:
    LeetCode算法题-Find Pivot Index(Java实现)
    LeetCode算法题-Longest Word in Dictionary(Java实现)
    LeetCode算法题-1-bit and 2-bit Characters(Java实现)
    2016-8-4学习正则表达式
    doT 这个模板 是怎么实现的?
    manually Invoking Model Binding / Model Binding /Pro asp.net mvc 5
    隐隐约约 听 RazorEngine 在 那里 据说 生成代码 很 美。
    web api 的 安全 认证问题 , 对外开放 的 时候 需要考虑到安全的问题
    鼠标滑过显示图片
    页面加载中效果实现
  • 原文地址:https://www.cnblogs.com/FallDream/p/bzoj4405.html
Copyright © 2011-2022 走看看