二分图刷题计划

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


[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\n",i-1);return 0;}}
    printf("%d\n",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\n");flag=1;break;}}
        if(!flag)printf("Yes\n");
    }
}

[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\n",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]]);
    }
}
posted @ 2018-11-03 09:24  蒟蒻--lichenxi  阅读(158)  评论(0编辑  收藏  举报