Luo Gu P1640 [SCOI2010] continuous attack game bipartite graph algorithms chain to the former Hungarian star

Topic links:

https://www.luogu.com.cn/problem/P1640

Reference blog:

https://www.luogu.com.cn/blog/xuanxue/solution-p1640

Blog is great, it is recommended to look at review

Algorithm: 1: Hungary Algorithm 2: Before the chain to star

Ideas:
1: man sister model, man is the attribute number 1-10000, the sister is the number of weapons 1-1000000

2: Let each and every property and equipment to even numbered side

3: attribute points from small to large order match, so we do not consider there will be no legal case, a time when we can not match attribute points i, we get the answer i-1

4: Hungarian algorithm is only used to build a one-way side, because every time we update when they are only use one side of the updated point, less than the other side of the point.

5: Another n = 106n = 10 ^ 6n = 106 when we can not always memset, or else it will time out, we record what point in time, when traversing look at the point in time is not a conflict can be. About this time stamp usage now, you can give a simple example of an analog look, very clever

#include <bits/stdc++.h>
//汉子妹子模型
//汉子是1到10000的属性编号,妹子是武器的编号1到1000000
using namespace std;
const int maxm=1e4+1,maxn=1e6+1;
int n,a,b,tot,now,head[maxm],vis[maxn],match[maxn];

struct edge
{
    int to,next;
}e[maxn<<1];//乘2

inline void add(int f,int t)//链式前向星
{
    e[++tot].to=t;
    e[tot].next=head[f];
    head[f]=tot;
}

inline int read()//读入优化
{
    char ch;int x=0,f=1;
    while(!isdigit(ch=getchar())){(ch=='-')&&(f=-f);}
    while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*f;
}

inline int dfs(int x)//匈牙利算法给每一个男孩子匹配妹子,给每一个属性匹配一把枪
{
    for(int i=head[x];i;i=e[i].next)
    {
        if(vis[e[i].to]==now)continue;
        vis[e[i].to]=now;
        if(!match[e[i].to]||dfs(match[e[i].to]))
        {
            match[e[i].to]=x;
            return 1;
        }
    }
    return 0;
}

int main()
{
    ios::sync_with_stdio(0);
    n=read();
    for(int i=1;i<=n;i++)
    {
        a=read(),b=read();
        add(a,i),add(b,i);//属性是汉子,武器的编号是妹子,建边,单向
    }
    for(int i=1;i<=10001;i++)
    {
        now=i;
        if(!dfs(i))//当我们某一次无法匹配属性点i的时候,我们就得到了答案i-1
        {
            cout<<i-1<<endl;
            return 0;
        }
    }
    return 0;
}

II: upper and thinking the same, but different codes wind, a reattachment

#include <bits/stdc++.h>

using namespace std;
const int maxm=1e4+1,maxn=1e6+1;
int first[maxm],book[maxn],match[maxn],n,tot,id,o;

struct edge
{
    int to,nex;
}e[maxn<<1];

inline void add(int f,int t)
{
    e[++tot].to=t;
    e[tot].nex=first[f];
    first[f]=tot;
}

inline bool dfs(int x)
{
    //first[i]初始值为-1,所以i+1,0时不运行
    for(int i=first[x],v;i+1;i=e[i].nex)
    {
        if(book[v=e[i].to]-id)
        {
            book[v]=id;
            if(!match[v]||dfs(match[v]))
            {
                match[v]=x;
                return true;
            }
        }
    }
    return false;
}

inline int contin()
{
    int ans=0;
    for(int i=id=1;i<=10000;i++,id++)
    {
        if(dfs(i))ans++;
        else break;
    }
    return ans;
}

int main()
{
    ios::sync_with_stdio(0);
    scanf("%d",&n);
    memset(first,-1,sizeof(first));
    for(int i=1;i<=n;i++)
        for(int j=0;j<2;j++)scanf("%d",&o),add(o,i);
    printf("%d\n",contin());
    return 0;
}

 

 

Published 117 original articles · won praise 37 · views 6565

Guess you like

Origin blog.csdn.net/aiwo1376301646/article/details/104229570