1 条题解

  • 0
    @ 2025-5-25 20:16:25

    二分查找区间长度:使用二分查找确定最小的区间长度 L。区间范围:左端点 st 从 1 到 m,右端点 (ed = st + L - 1)。二分图匹配检查:对于每个候选区间 ([st, ed]),构建二分图:左侧节点为用户,右侧节点为物品。左侧节点只能匹配其偏好列表中位置在 ([st, ed]) 内的物品。使用匈牙利算法检查是否存在完美匹配。容量约束处理:右侧节点 y 的容量为 (b[y]),最多可匹配 (b[y]) 个左侧节点。在匈牙利算法中,当右侧节点已满时,尝试替换已有匹配以腾出空间。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<queue>
    using namespace std;
    const int Maxn=1000+5;
    int n,m,ans,mp[Maxn][25],b[Maxn];
    int st,ed,cnt[Maxn],matched[25][Maxn];
    bool vis[Maxn];
    bool found(int x)
    {	
    	for(int i=st;i<=ed;i++)
    	{	
    		int y=mp[x][i];
    		if(vis[y])continue;
    		vis[y]=1;
    		if(cnt[y]<b[y])
    		{	
    			matched[y][++cnt[y]]=x;
    			return 1;
    		}
    		else{
    			for(int j=1;j<=cnt[y];j++)
    				if(found(matched[y][j]))
    				{	
    					matched[y][j]=x;
    					return 1;
    				}
    		}
    	}
    	return 0;
    }
    int match()
    {	
    	int res=0;
    	memset(matched,0,sizeof(matched));
    	memset(cnt,0,sizeof(cnt));
    	for(int i=1;i<=n;i++)
    	{	
    		memset(vis,0,sizeof(vis));
    		if(found(i))res++;
    	}
    	return res;
    }
    bool check(int len)
    {	
    	for(st=1;st<=m;st++)
    	{	ed=st+len-1;
    		if(ed>m)break;
    		if(match()==n)return 1;
    	}
    	return 0;
    }
    int main()
    {	
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=m;j++)
    			scanf("%d",&mp[i][j]); 
    	for(int i=1;i<=m;i++)
    		scanf("%d",&b[i]);
    	int l=0,r=m,mid;
    	while(l<=r)
    	{	
    		mid=(l+r)>>1;
    		if(check(mid))ans=mid,r=mid-1;
    		else l=mid+1;
    	}
    	printf("%d\n",ans);
    	return 0;
    }
    
    
    • 1

    信息

    ID
    2190
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者