1 条题解
-
0
二分查找区间长度:使用二分查找确定最小的区间长度 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
- 上传者