链接:http://poj.org/problem?id=1149
构图果然很关键。这是参考他人的构图。
思路:对于某个猪圈i,设拥有这个猪圈钥匙的人序列为Pi1,Pi2...Pij,则从源向Pi1连一条容量为猪圈i初始猪数的边(记得容量为累加),在相邻两个点之间连无穷大边,每个点到汇点连一条容量为需求量的边.然后求最大流即可。
构图好后,用最大流的算法做就可以了。
不过这个题,我用邻接矩阵的SAP做,交了N次WA。。。。不知道还有什么地方有错了啊。。。
然后无奈用Dinic做了,1A。
关键是我不知道我的SAP有没有错啊。以后还得靠这模板混日子呢。。。。
#include<cstdio>
#include<cstring>
#include<queue>
#define INF 99999999
#define MAXN 1200
#define MAXM 12000
#define MIN(a,b) a>b?b:a
using namespace std;
struct HOUSE
{
int pigs;
int last;
};
HOUSE house[MAXM];
int m,n;//m表示猪圈数目,n表示顾客数目
int flow;
int map[MAXN][MAXN];
int st,ed;
int cust[MAXN];
int dist[MAXN];
int BFS()
{
memset(dist,-1,sizeof(dist));
int i,tmp;
dist[st]=0;//汇点n+1的层次为0
queue<int> q;
q.push(st);
while(!q.empty())
{
tmp=q.front();
q.pop();
for(i=0;i<=ed;i++)
{
if(dist[i]==-1&&map[tmp][i]>0)
{
dist[i]=dist[tmp]+1;
q.push(i);
}
}
}
if(dist[ed]>0)
return 1;
return 0;
}
int DFS(int x,int low)
{
int i,a;
if(x==ed)
return low;
for(i=0;i<=ed;i++)
{
if(map[x][i]>0&&dist[i]==dist[x]+1&&(a=DFS(i,MIN(low,map[x][i]))))
{
map[x][i]-=a;
map[i][x]+=a;
return a;
}
}
return 0;
}
void Dinic()
{
int res;
while(BFS())
{
while((res=DFS(0,INF)))
flow+=res;
}
return ;
}
int main()
{
int key,open;
while(scanf("%d%d",&m,&n)!=EOF)
{
memset(map,0,sizeof(map));
memset(cust,0,sizeof(cust));
st=0; //源点
ed=n+1; //汇点
for(int i=1;i<=m;i++)
{
scanf("%d",&house[i].pigs);
house[i].last=0;
}
for(int i=1;i<=n;i++)
{
scanf("%d",&key);
for(int j=0;j<key;j++)
{
scanf("%d",&open);
if(!house[open].last)
{
map[st][i]+=house[open].pigs;//如果这个猪圈是第一次被访问,则边权是猪圈原有的猪的数量
house[open].last=i; //记录此时客人的标号
}
else
{
map[house[open].last][i]=INF;//如果此猪圈之前已经被访问,则当前顾客和之前顾客之间建立边权为INF的边
house[open].last=i;
}
}
scanf("%d",&cust[i]);
map[i][ed]=cust[i];//ed为汇点,当前顾客和汇点建立边权为顾客所需的猪的数量的边
}
flow=0;
Dinic();
printf("%d\n",flow);
}
return 0;
}
//SAP怎么都过不了啊,郁闷。
/*
#include<cstdio>
#include<cstring>
#include<queue>
#define INF 99999999
#define MAXN 1200
#define MAXM 12000
#define MIN(a,b) a>b?b:a
using namespace std;
struct HOUSE
{
int pigs;
int last;
};
HOUSE house[MAXM];
int m,n;//m表示猪圈数目,n表示顾客数目
int maxflow;
int map[MAXN][MAXN];
int st,ed;
int cust[MAXN];
int dist[MAXN];
int gap[MAXN];
int pre[MAXN];
void BFS(int ed)
{
memset(dist,-1,sizeof(dist));
memset(gap,0,sizeof(gap));
int i;
dist[ed]=0;//汇点n+1的层次为0
gap[dist[ed]]++;
queue<int> q;
q.push(ed);
while(!q.empty())
{
int tmp=q.front();
q.pop();
for(i=0;i<=ed;i++)
{
if(dist[i]==-1&&map[i][tmp]>0)
{
dist[i]=dist[tmp]+1;
gap[dist[i]]++;
q.push(i);
}
}
}
}
void SAP(int st,int ed)
{
BFS(ed);
//memset(pre,-1,sizeof(pre));
int top,aug=INF,i,j,k,flag,mindis;
top=pre[st]=st;
//gap[0]=n+2;
while(dist[st]<ed+1)
{
flag=0;
for(i=0;i<=ed;i++)
{
if(map[top][i]>0&&dist[top]==dist[i]+1)
{
flag=1;
break;
}
}
if(flag)
{
aug=MIN(aug,map[top][i]);
pre[i]=top;
top=i;
if(top==ed)
{
maxflow+=aug;
j=top;
while(j!=st)
{
k=pre[j];
map[k][j]-=aug;
map[j][k]+=aug;
j=k;
}
top=st;
aug=INF;
}
}
else
{
gap[dist[top]]--;
if(gap[dist[top]]==0)
return;
mindis=ed+10;
for(j=0;j<=ed;j++)
{
if(map[top][j]>0&&mindis>dist[j]+1)
mindis=dist[j]+1;
}
dist[top]=mindis;
gap[dist[top]]++;
if(st!=top)
top=pre[top];
}
}
return ;
}
int main()
{
int key,open;
while(scanf("%d%d",&m,&n)!=EOF)
{
memset(map,0,sizeof(map));
memset(cust,0,sizeof(cust));
st=0;
ed=n+1;
for(int i=1;i<=m;i++)
{
scanf("%d",&house[i].pigs);
house[i].last=-1;
}
for(int i=1;i<=n;i++)
{
scanf("%d",&key);
for(int j=0;j<key;j++)
{
scanf("%d",&open);
if(house[open].last==-1)
{
map[st][i]+=house[open].pigs;
house[open].last=i;
}
else
{
map[house[open].last][i]=INF;
house[open].last=i;
}
}
scanf("%d",&cust[i]);
map[i][ed]=cust[i];
}
maxflow=0;
SAP(st,ed);
printf("%d\n",maxflow);
}
return 0;
}
*/