题目描述:现有N个(16)不同的材料,编号从1~N。
有M(50000)个模型,每个模型都需要一些材料才能完成。
给你每个模型需要的材料是什么。
问你最多能完成多少个模型。(注意,N个材料每个仅能用一次)。
解题报告:
由于每个材料只能用一次,所以最多也就是能个完成16个模型了。
建图:
N个材料拆点,i号材料为点i和点i+n
连接所有的点i和i+n,容量1。(限制每个点仅用一次)
对于每个模型需要的材料 排序 后,为x1,x2 …… xm
源点s = 0,连接x1
汇点t = n + n + 1, 和xm(最后一个连接)
其余的xi + n连接xi + 1.
这样就保证s所连接的是起点,t所连接的是终点。
并且每一个从s到t的通路都是一个模型的方案。
同时每个点由于拆点限制了只能用一次。
所以最大流就是答案。
代码如下:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
#define size 50
#define Max 0x1fffffff
int cap[size][size],s,t,n;
int queue[size],head,tail, Flow,prev[size];
bool
findload()
//bfs找增广路径
{
int i, tmp;
memset(prev,-1,sizeof(prev));
head = tail = 0;;
queue[tail++] = s;
prev[s] = s;
while(head < tail)
{
tmp = queue[head++];
for(i = 0; i <
n; i++)
if(prev[i] ==
-1 && cap[tmp][i] >
0)
{
prev[i]
= tmp;
if
(i == t) return true;
queue[tail++]
= i;
}
}
return false;
}
int maxflow()
{
Flow =
0;
while(findload())
{
int min = Max;
for(int i = t; i != s; i =
prev[i]) //增广路径中的最小可通过流
if(min
> cap[prev[i]][i])
min
= cap[prev[i]][i];
for(int i = t; i != s; i =
prev[i])//调整路径上的流
{
cap[prev[i]][i]
-= min;
cap[i][prev[i]]
+= min;
}
Flow +=
min; //最大流累加
}
return Flow;
}
int a, b, jeo[16], cnt;
int main()
{
while(scanf("%d%d", &a, &b) !=
EOF)
{
memset(cap, 0, sizeof(cap));
s = 0, t = a + a + 1; n = t + 1;
for(int i = 1; i <= a; i++) cap[i][i + a] = 1;
while(b--)
{
int tmp; scanf("%d", &tmp);
for(int i = 0; i < tmp; i++)scanf("%d",
&jeo[i]);
sort(jeo, jeo + tmp);
cap[s][jeo[0]] = 1;cap[jeo[tmp - 1]][t] = 1;
for(int i = 0; i < tmp - 1; i++)
cap[jeo[i] + n][jeo[i + 1]] = 1;
}
printf("%d\n", maxflow());
}
return
0;
}
加载中,请稍候......