hdoj 3729 I'm Telling the Truth (二分图匹配)

版权声明:欢迎神犇指教 https://blog.csdn.net/sdxtcqs/article/details/81813089

http://acm.hdu.edu.cn/showproblem.php?pid=3729
题意:n个人,每个人说自己排名在x~y名,问最多几个人说的是真话,输出最多的人数,和字典序最大的这几个人的编号。
数据范围:n <= 60,1 <= Xi <= Yi <= 100000

当时看到x,y的数据范围是有点被吓住了,但n只有60,而且我也不会什么其他方法,所以就对每个人对从Xi到Yi的每一个数都连一条边,然后暴力跑匈牙利算法,竟然卡过了,先T了几回,突然967ms卡过了,再后来再交又是T了,结果发现是因为我把vis数组开得太大了,每次匹配都要memset结果就疯狂T,真是太菜了。。。
这里写图片描述
而且上网查题解发现,发我的思路没错,就是要暴力,只是建图不需要每条边都存,记录一个x,y就行,每次遍历这个人的每条边就从x到y循环就行,这样空间也能省下很多。
这里还有一个点就是输出字典序最大的答案序列,其实很简单匹配的时候倒着循环,每次尽量先找大的,就能得到字典序最大的了。
还有个会PE的点就是每行末尾不能有空格,每组数据最后都有回车。
我的渣渣版本:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <map>
#include <set>
using namespace std;
int ans[65];
int n,m,T,k;
bool vis[100005];//就是这个数组我之前多打了一个0就导致疯狂T
map<int,int> pr;
struct Edge{
    int w,v,next;
}e[1000010];
int head[1000010];
void addedge(int u,int v,int w)
{
    e[k].v=v;
    e[k].w=w;
    e[k].next=head[u];
    head[u]=k++;
}
bool find(int x)
{
    for(int i=head[x];i;i=e[i].next)
    {
        if(!vis[e[i].v])
        {
            vis[e[i].v]=1;
            if(pr[e[i].v]==0||find(pr[e[i].v]))
            {
                pr[e[i].v]=x;
                return 1;
            }
        }
    }
    return 0;
}
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        k=1;
        scanf("%d",&n);
        int sum=0,num=0;
        pr=map<int,int>();
        memset(e,0,sizeof(e));
        memset(head,0,sizeof(head));
        for(int i=1;i<=n;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            for(int j=x;j<=y;j++)
                addedge(i,j,1);
        }
        for(int i=n;i>=1;i--)//倒序循环
        {
            memset(vis,0,sizeof(vis));
            if(find(i)) sum++;
        }
        printf("%d\n",sum);
        map<int,int>::iterator it;
        for(it=pr.begin();it!=pr.end();it++)
        {
            num++;
            ans[num]=it->second;
        }
        sort(ans+1,ans+1+num);
        for(int i=1;i<num;i++)
            printf("%d ",ans[i]);
        printf("%d",ans[num]);
        printf("\n");
    }
    return 0;
}

借鉴题解后的改良版本

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <map>
#include <set>
using namespace std;
int ans[65];
int n,m,T,k;
bool vis[100005];
map<int,int> pr;
struct Edge{
    int x,y;
}e[100];//空间一下次省了好多
bool find(int p)
{
    for(int i=e[p].x;i<=e[p].y;i++)
    {
        if(!vis[i])
        {
            vis[i]=1;
            if(pr[i]==0||find(pr[i]))
            {
                pr[i]=p;
                return 1;
            }
        }
    }
    return 0;
}
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        k=1;
        scanf("%d",&n);
        int sum=0,num=0;
        pr=map<int,int>();
        memset(e,0,sizeof(e));
        for(int i=1;i<=n;i++)
            scanf("%d%d",&e[i].x,&e[i].y);
        for(int i=n;i>=1;i--)
        {
            memset(vis,0,sizeof(vis));
            if(find(i)) sum++;
        }
        printf("%d\n",sum);
        map<int,int>::iterator it;
        for(it=pr.begin();it!=pr.end();it++)
        {
            num++;
            ans[num]=it->second;
        }
        sort(ans+1,ans+1+num);
        for(int i=1;i<num;i++)
            printf("%d ",ans[i]);
        printf("%d",ans[num]);
        printf("\n");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/sdxtcqs/article/details/81813089