额。。。这是SHTSC2011 第五轮的题。
【题意】
有 M 个猪圈(M ≤ 1000),每个猪圈里初始时有若干头猪。一开始所有猪圈都是关闭的。 依次来了 N 个顾客(N ≤ 100),每个顾客分别会打开指定的几个猪圈,从中买若干头猪。 每个顾客分别都有他能够买的数量的上限。 每个顾客走后,他打开的那些猪圈中的猪,都可以被任意地调换到其它开着的猪圈里,然后所有猪圈重新关上。
【题解】
网络流,关键在如果顾客j在顾客i之后买猪,且他们有相同的猪圈的钥匙,则j向i连边。其余略。
【代码】
#include <iostream>
#include <vector>
using namespace std;
const int oo=9999999,maxn=1200,maxm=100000;
struct edge
{
int x,y,f,next,op;
}e[maxm];
int h[maxn],d[maxn],p[maxn],now[maxn],num[maxn],bb[105],a[105][1005],c[1005];
bool v[105][105];
vector<int> b[1005];
int n,m,s,t,tot;
void ins(int x,int y,int f)
{
e[++tot].x=x;e[tot].y=y;
e[tot].next=h[x];e[tot].f=f;
h[x]=tot;
e[++tot].x=y;e[tot].y=x;
e[tot].next=h[y];e[tot].f=0;
h[y]=tot;
e[tot].op=tot-1;e[tot-1].op=tot;
}
int isap()
{
int flow=0,aug=oo,u,v,tmp,i,j,ff;
for (i=0;i<=t;i++)
{
d[i]=0;p[i]=-1;
num[i]=0;now[i]=h[i];
}
num[0]=t+1;u=s;
while (d[s]<t+1)
{
for (ff=0,i=now[u];i;i=e[i].next)
{
v=e[i].y;
if (e[i].f && d[u]==d[v]+1)
{
ff=1;
if (e[i].f<aug) aug=e[i].f;
p[v]=i;now[u]=i;
u=v;
if (u==t)
{
flow+=aug;
while (u!=s)
{
j=p[u];
e[j].f-=aug;
e[e[j].op].f+=aug;
u=e[j].x;
}
aug=oo;
}
break;
}
}
if (ff) continue;
num[d[u]]--;
if (!num[d[u]]) return flow;
tmp=t+1;
for (i=h[u];i;i=e[i].next)
{
v=e[i].y;
if (e[i].f && d[v]<tmp)
{
tmp=d[v];now[u]=i;
}
}
d[u]=tmp+1;
num[d[u]]++;
if (u!=s) u=e[p[u]].x;
}
return flow;
}
int main()
{
freopen("pin.txt","r",stdin);
freopen("pou.txt","w",stdout);
int i,j,k;
scanf("%d%d",&m,&n);
for (i=1;i<=m;i++)
scanf("%d",&c[i]);
for (i=1;i<=n;i++)
{
scanf("%d",&a[i][0]);
for (j=1;j<=a[i][0];j++)
{
scanf("%d",&a[i][j]);
b[a[i][j]].push_back(i);
}
scanf("%d",&bb[i]);
}
s=0;t=n+m+1;
for (i=1;i<=n;i++)
ins(s,i,bb[i]);
for (i=1;i<=m;i++)
ins(i+n,t,c[i]);
for (i=1;i<=n;i++)
for (j=1;j<=a[i][0];j++)
ins(i,a[i][j]+n,oo);
for (i=1;i<=m;i++)
for (j=0;j<b[i].size();j++)
for (k=0;k<b[i].size();k++)
if (b[i][j]>b[i][k])
if (!v[b[i][j]][b[i][k]])
{
ins(b[i][j],b[i][k],oo);
v[b[i][j]][b[i][k]]=true;
}
cout << isap() << endl;
return 0;
}