题目链接:UVa 11045 - My T-shirt suits me
最大流。
设一个原点0,1到6为六种型号衣服对应的点,然后7到m+6是m个人对应的点,最后一个点m+7对应汇点。原点到型号点的容量为n/6(根据题意),一个人对应两种型号衣服,每条线的容量都是1(每个人对应两种衣服),最后每个人到终点的容量都为1(每个人只需要一件衣服)。这样图就建好了。
如果最后流到汇点的流量为m,则表示可以,否则不可以。
#include <iostream>
#include <queue>
#include <cstring>
using namespace std;
const int MAX_N = 36 + 6;
const int INF = (1 << 30);
int n,m,T,s,t;
int cap[MAX_N][MAX_N],flow[MAX_N][MAX_N],p[MAX_N];
int maxFlow()
{
queue<int> q;
int ans = 0,a[MAX_N];
while(true)
{
q.push(s);
memset(a, 0, sizeof(a));
a[s] = INF;
while (!q.empty())
{
int u = q.front();
q.pop();
for (int i = 0; i <= t; i++)
{
if (!a[i] && cap[u][i] > flow[u][i])
{
p[i] = u;
q.push(i);
a[i] = min(a[u],cap[u][i] - flow[u][i]);
}
}
}
if (a[t] == 0)
break;
for (int i = t;i != s;i = p[i])
{
flow[p[i]][i] += a[t];
flow[i][p[i]] -= a[t];
}
ans += a[t];
}
return ans;
}
int num(string s)
{
if(s == "XS")
return 1;
else if(s == "S")
return 2;
else if(s == "M")
return 3;
else if(s == "L")
return 4;
else if(s == "XL")
return 5;
else if(s == "XXL")
return 6;
}
int main()
{
cin >> T;
while(T--)
{
memset(flow,0,sizeof(flow));
memset(cap,0,sizeof(cap));
cin >> n >> m;
s = 0;
t = m + 7;
int f = n / 6;
for (int i = 7;i <= 6 + m;i++)
{
string a, b;
cin >> a >> b;
cap[num(a)][i] = 1;
cap[num(b)][i] = 1;
cap[i][t] = 1;
}
for ( int i = 1; i <= 6; i++)
cap[0][i] += f;
int ans = maxFlow();
if (ans < m)
cout << "NO" << endl;
else
cout << "YES" << endl;
}
return 0;
}