这道题知道用二分图匹配+二分,但是真的不好想。。到现在我还是云里雾里的。。
先附上大佬博客Orz:https://www.cnblogs.com/zhengguiping--9876/p/5675712.html
一开始题目就没太懂,看了解释发现,,没思路啊55555...看了大佬博客发现,可以二分枚举区间长度啊。。然后对应dfs里的条件要换。。
附上AC代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=1005;
const int MAXM=25;
int un,vn;
int g[MAXN][MAXM];
int link[MAXN][MAXM];
bool vis[MAXM];
int num[MAXM],cnt[MAXM];
bool dfs(int u,int l,int r)
{
for(int v=1;v<=vn;v++)
if(!vis[v]&&g[u][v]<=r&&g[u][v]>=l)//注意条件
{
vis[v]=true;
if(cnt[v]<num[v])
{
link[v][cnt[v]++]=u;
return true;
}
for(int i=0;i<cnt[v];i++)//注意此处仍从0开始
if(dfs(link[v][i],l,r))
{
link[v][i]=u;
return true;
}
}
return false;
}
int hungary(int l,int r)
{
memset(link,0,sizeof(link));
memset(cnt,0,sizeof(cnt));
for(int u=1;u<=un;u++)
{
memset(vis,false,sizeof(vis));
if(!dfs(u,l,r))
return false;
}
return true;
}
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)==2)
{
memset(g,0,sizeof(g));
int x;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
scanf("%d",&x);
g[i][x]=j;
}
for(int i=1;i<=m;i++)
scanf("%d",&num[i]);
un=n,vn=m;
int l=0,r=m;//二分的是区间长度
while(l<r)
{
int i,mid=(l+r)/2;
for(i=1;i<=m;i++)
{
if(hungary(i,mid+i))//枚举区间大小为mid+1的值,满足条件时则取其最小值
break;
}
if(i<=m)
r=mid;
else
l=mid+1;
}
printf("%d\n",l+1);
}
return 0;
}