题目意思就不解释了,实际上是求二分图的最大多重匹配,这里有个比较好的定义和总结,可以看看:
http://www.cppblog.com/MatoNo1/archive/2011/03/26/142766.aspx
个人理解,就是二分图中的两部分图X和Y,若要找出其中的匹配且使得结点数较多的那部分B中,每个结点均有相匹配的点在另外一部分图A中,此时A中必存在点其与多条匹配边相关联。此时可以匈牙利算法解决这种二分图多重匹配问题,即求出点与匹配边的最大关联数(或者是找出一个点,使得它在多重匹配中相关联的最多边数在一定上限值内最小),此时match数组是二维的,第二维是记录与第2个集合里的节点v第i次匹配成功的节点的标号,其余的和原始的匈牙利算法相同。
以下是poj 2289的代码:
- #include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=1070; - struct node
{
int v;
int next;
}edge[N*N];
int head[N],num;
int match[N/2][N],Num[N/2];
bool vis[N];
int n,m; - void init()
{
int i;
for(i=0;i<=n+m+1;i++)
head[i]=-1;
num=0;
} - void addege(int u,int v)
{
edge[num].v=v;
edge[num].next=head[u];
head[u]=num++;
} - bool find(int u,int mid)
{
int i,j;
for(i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].v;
if(!vis[v])
{
vis[v]=true;
if(Num[v]<mid)
{
match[v][++Num[v]]=u;
return true;
}
for(j=1;j<=mid;j++)
{
if(find(match[v][j],mid))
{
match[v][j]=u;
return true;
}
}
}
}
return false;
} - int main()
{
freopen("in.txt","r",stdin);
while(scanf("%d%d",&n,&m)==2)
{
if(!n && !m) break;
init();
int i,u,v=1;
char s[20],ch;
for(i=1;i<=n;i++)
{
scanf("%s",s);
while(1)
{
scanf("%d",&v);
ch=getchar();
addege(i,v);
if(ch=='/n') break;
}
}
int low=1,high=n;
int ans=0;
while(low<=high)
{
int mid=(low+high)/2;
memset(match,-1,sizeof(match));
memset(Num,0,sizeof(Num));
bool flag=true;
for(i=1;i<=n;i++)
{
memset(vis,0,sizeof(vis));
if(!find(i,mid))
{
flag=false;break;
}
}
if(flag)
{
ans=mid;high=mid-1;
}
else
low=mid+1;
}
printf("%d/n",ans);
}
return 0;
}
这里是poj 1698的解题报告。其实也是一个二分图的多重匹配,用最大流做的。以电影和工作日期(要把星期展开成天)为二分图构图,加上一个超级源点和超级汇点,电影和日期间的边的容量是inf,而源点到电影,汇点到日期的边的容量是1,进行一次最大流算法以后,检查所得最大流是否等于所有电影日期的总和,是则“yes”,否则就是“no"。
以下是代码:
- #include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int M=40000;
const int N=500;
const int inf=1<<29; - struct node
{
int v,f;
int next;
}edge[M];
int head[N],num;
int work[30],d,w;
int s,t,flow,maxweek,NN;
int n,m; - void init()
{
int i;
memset(head,-1,sizeof(head));
num=flow=0;
s=0;
maxweek=-1;
} - void addege(int u,int v,int f)
{
edge[num].v=v;
edge[num].f=f;
edge[num].next=head[u];
head[u]=num++;
edge[num].v=u;
edge[num].f=0;
edge[num].next=head[v];
head[v]=num++;
} - void sap()
{
int pre[N],cur[N],dis[N],gap[N];
int aug=inf,u;
bool flag;
int i;
for(i=0;i<=NN;i++)
{
dis[i]=gap[i]=0;
cur[i]=head[i];
}
gap[s]=NN;
u=pre[s]=s;
while(dis[s]<NN)
{
flag=0;
for(int &j=cur[u];j!=-1;j=edge[j].next)
{
int v=edge[j].v;
if(edge[j].f>0 && dis[u]==dis[v]+1)
{
flag=1;
if(edge[j].f<aug) aug=edge[j].f;
pre[v]=u;
u=v;
if(u==t)
{
flow+=aug;
while(u!=s)
{
u=pre[u];
edge[cur[u]].f-=aug;
edge[cur[u]^1].f+=aug;
}
aug=inf;
}
break;
}
}
if(flag) continue;
int mindis=NN;
for(j=head[u];j!=-1;j=edge[j].next)
{
int v=edge[j].v;
if(edge[j].f>0 && dis[v]<mindis)
{
mindis=dis[v];
cur[u]=j;
}
}
if((--gap[dis[u]])==0) break;
gap[dis[u]=mindis+1]++;
u=pre[u];
}
} - int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
init();
int i,j,k;
int sum=0;
for(i=1;i<=n;i++)
{
for(j=0;j<7;j++)
scanf("%d",&work[j]);
scanf("%d%d",&d,&w);
sum+=d;
if(w>maxweek) maxweek=w;
addege(s,i,d);
for(j=0;j<w;j++)
{
for(k=0;k<7;k++)
if(work[k])
{
addege(i,j*7+n+k+1,inf);
}
}
}
t=n+maxweek*7+1;
NN=t+1;
for(i=0;i<maxweek;i++)
for(j=1;j<=7;j++)
addege(i*7+n+j,t,1);
sap();
if(flow==sum)
printf("Yes/n");
else
printf("No/n");
}
return 0;
}