• 二分图刷题计划


    最近忽然想刷二分图
    在赛前去洛谷做了做二分图的题目


    [SCOI2010]连续攻击游戏

    我们很容易发现每选用一个物品,只能采取一个属性值,那么另一个属性值就无法使用了,我们无法确定应该用哪个属性值,这就比较难找到最优的选择。

    我们就可以考虑将一个属性值为(x,y)的物品(i)处理一下,将(x->i,y->i)连边,然后就可以保证任意一个物品都只选择了一个属性,建出二分图跑一遍最大匹配即可得到最优解,由于属性连续,所以找到第一个不可匹配的就要退出。

    这题数据范围是真的fake,据说最大的数据才(7e4),数据范围写的(1e6)好多暴力都跑过去了,按理说匈牙利也不可能过的。

    代码(匈牙利板子):

    #include<cstdio>
    #include<cstring>
    using namespace std;
    int n,cnt,pre[2000001],nxt[2000001],h[1000001],vis[2000001];bool used[2000001];
    void add(int x,int y){pre[++cnt]=y;nxt[cnt]=h[x];h[x]=cnt;}
    bool dfs(int x)
    {
        for(int i=h[x];i;i=nxt[i])
            if(!used[pre[i]]) 
            {
                used[pre[i]]=1;
                if(!vis[pre[i]]||dfs(vis[pre[i]]))
                {
                    vis[pre[i]]=x;
                    return 1;
                }
            }
        return 0;
    }
    int main()
    {
        scanf("%d",&n);
        for(int i=1,x,y;i<=n;i++)scanf("%d%d",&x,&y),add(x,i+n),add(y,i+n);
        for(int i=1;i<=n;i++){memset(used,0,sizeof used);if(!dfs(i)){printf("%d
    ",i-1);return 0;}}
        printf("%d
    ",n);
    }
    

    [ZJOI2007]矩阵游戏

    这道题我一开始想的就是只要每行每列都有一个(1)就可以了,这是不是很愚蠢。。。

    随手hack:

    显然是(No),但是如果按我之前的想法就错了。

    但是思想还是对的,只要每行和每列匹配上就行了。

    但是交换会影响多个点。

    我们暂时只考虑行匹配完全,

    于是我们考虑对于每个黑点,他的位置((i,j)),就意味着他能通过列交换使第(i)行匹配上。

    所以我们只要将对于所有黑点连边,最后求一遍最大匹配,判断一下最大匹配是否是(n)就行了。

    显然是(n)(Yes),否则(No)

    代码;

    #include<cstdio>
    #include<cstring>
    using namespace std;
    int t,n,mp[201][201],f[201];bool vis[201],flag;
    bool dfs(int x){for(int i=1;i<=n;i++)if(!vis[i]&&mp[x][i]){vis[i]=1;if(!f[i]||dfs(f[i])){f[i]=x;return 1;}}return 0;}
    int main()
    {
        scanf("%d",&t);
        while(t--)
        {
            memset(f,0,sizeof f);
            scanf("%d",&n);flag=0;
            for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++)
                    scanf("%d",&mp[i][j]);
            for(int i=1;i<=n;i++){memset(vis,0,sizeof vis);if(!dfs(i)){printf("No
    ");flag=1;break;}}
            if(!flag)printf("Yes
    ");
        }
    }
    

    [SHOI2001]小狗散步

    这个题真的只是难在建图,好像还是比较麻烦,所以我看了题解,然后就变成了sb题(我就是个sb)。对于每个相遇点枚举狗是否可以去他感兴趣的景点,连边跑二分图最大匹配就行了。我连算距离都能写错,我是个人才,不如滚回去学数学。。。

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    using namespace std;
    int n,m,f[101],ans,vis[101],d[101][101];double l[101],r[101],x[101],y[101];
    bool dfs(int x)
    {
        for(int i=1;i<n;i++)
            if(d[x][i]&&!vis[i])
            {
                vis[i]=1;
                if(!f[i]||dfs(f[i])){f[i]=x;return 1;}
            }
        return 0;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)scanf("%lf%lf",&x[i],&y[i]);
        for(int i=1;i<=m;i++)scanf("%lf%lf",&l[i],&r[i]);
        for(int i=1;i<n;i++)
        {
            double now=sqrt((x[i+1]-x[i])*(x[i+1]-x[i])+(y[i+1]-y[i])*(y[i+1]-y[i]));
            for(int j=1;j<=m;j++)
            {
                double g=(x[i]-l[j])*(x[i]-l[j])+(y[i]-r[j])*(y[i]-r[j]);g=sqrt(g);
                g+=sqrt((x[i+1]-l[j])*(x[i+1]-l[j])+(y[i+1]-r[j])*(y[i+1]-r[j]));
                if(g<=now*2)d[j][i]=1;
            }
        }
        for(int i=1;i<=m;i++)
        {
            memset(vis,0,sizeof vis);
            if(dfs(i))ans++;
        }
        printf("%d
    ",ans+n);
        for(int i=1;i<=n;i++)
        {
            printf("%.0lf %.0lf ",x[i],y[i]);
            if(f[i])printf("%.0lf %.0lf ",l[f[i]],r[f[i]]);
        }
    }
    
  • 相关阅读:
    Java并发与线程同步
    ArrayList源码分析
    Lock之ReentrantLock及实现生产者消费者和死锁
    SimpleDateFormat线程不安全原因及解决方案
    JDK1.7 hashMap源码分析
    java 数据操作
    java 数据流操作
    java 基础概念
    获取class 信息 java
    Java虚拟机系列(三)---内存溢出情况及解决方法
  • 原文地址:https://www.cnblogs.com/lcxer/p/9899651.html
Copyright © 2020-2023  润新知