题意:n个顾客依次来买猪,有n个猪房,每个顾客每次可以开若干个房子,买完时,店主可以调整这位顾客

开的猪房里的猪,共m个猪房,每个猪房有若干猪,求最多能卖多少猪。

构图思想:顾客有先后,每个人想要的猪数量已经确定,显然要建汇点t,每个顾客连线t(以顾客为结点),权值为他想要买

的猪数量(最多想要的都卖了,最大流之归宿,必思汇点!)然后,你想,每个顾客有先后顺序,前一个顾客开过的

房子取的猪数量可以重新分配必然要连后一个开这个房子的顾客连线(权为inf)(相当于前面一个先取该流量,后面的再取,重新分配)

这样建图!如果没有开过的房子怎么办?建立超级源点啊,权值为房子猪数量。这个可以用一个链来存储,

下面代码中fa【】数组实现之即可,记录前一个开过的顾客号码,没有开过的用s连他。



此题经典啊(被大牛定位较难题),关键是这种构图思想。小结一下:先思源汇点(看最大情况),再思哪些作为结点好,

这题每个结点之间有限制,故在先的结点先取源流,再通向下一个被限制的点,这思想很重要。

关于网上流传的简化图三规则,若是或字关系,是错的:

规律1. 如果几个结点的流量的来源完全相同,则可以把它们合并成一个.

规律2. 如果几个结点的流量的去向完全相同,则可以把它们合并成一个.

规律3. 如果从点u到点v有一条容量为∞的边,并且点v除了点u以外没有别的流量来源,则可以把这两个结点合并成一个.

,符合规则1或2,随便举个例子就错了,我认为1,2合为一条,

必需同时满足才可以合并。

#include<iostream>  //16 ms 1A
#include<cstdio>
#include<queue>
using namespace std;
int m,n;int numpig[1010];int fa[1010];
int e[10000][3];int nume;int head[110]; const int inf=0x3f3f3f3f;
void addedge(int from,int to,int w)
{
e[nume][0]=to; e[nume][1]=head[from];head[from]=nume;
e[nume++][2]=w;
e[nume][0]=from; e[nume][1]=head[to];head[to]=nume;
e[nume++][2]=0;
}
int level[120];int vis[120];
bool bfs() //dinic
{
for(int i=0;i<=n+1;i++)
vis[i]=level[i]=0;
queue<int>q;q.push(0);
vis[0]=1;
while(!q.empty())
{
int cur=q.front();q.pop();
for(int i=head[cur];i!=-1;i=e[i][1])
{ int v=e[i][0];
if(!vis[v]&&e[i][2]>0)
{
level[v]=level[cur]+1;
if(v==1+n)return 1;
vis[v]=1;
q.push(v);
}
}
}
return vis[1+n];
}
int dfs(int u,int minf)
{
if(u==1+n||minf==0)return minf;
int sumf=0,f;
for(int i=head[u];i!=-1&&minf;i=e[i][1])
{ int v=e[i][0];
if(level[v]==level[u]+1&&e[i][2]>0)
{
f=dfs(v,minf<e[i][2]?minf:e[i][2]);
e[i][2]-=f;e[i^1][2]+=f;
minf-=f;sumf+=f;
}
}
return sumf;
}
int dinic()
{
int sum=0;
while(bfs())
{
sum+=dfs(0,inf);
}
return sum;
}
int main()
{
scanf("%d%d",&m,&n);
for(int i=1;i<=m;i++)
{
scanf("%d",&numpig[i]);
fa[i]=0;
}
for(int i=0;i<=n+1;i++)
head[i]=-1;
nume=0;
int numkey,house,numwant;
for(int i=1;i<=n;i++) //构图
{
scanf("%d",&numkey);
while(numkey--)
{
scanf("%d",&house);
addedge(fa[house],i,fa[house]==0?numpig[house]:inf);
fa[house]=i;
}
scanf("%d",&numwant);
addedge(i,n+1,numwant);
}
int ans=dinic();
printf("%d\n",ans);
return 0;
}

最新文章

  1. C#中的委托与事件并存的理由
  2. SQL——索引
  3. 【Android UI设计与开发】第05期:引导界面(五)实现应用程序只启动一次引导界面
  4. spring替代方法
  5. 奇异值分解(SVD) --- 几何意义
  6. bzoj 1833 [ZJOI2010]count 数字计数(数位DP)
  7. void及void指针含义的深刻解析
  8. Android(java)学习笔记199:Android中补间动画(Tween Animation)
  9. Jfinal控制器源码解读
  10. fread和fwrite的使用
  11. ArcGIS License启动无响应
  12. js和jquery实现显示隐藏
  13. 代理模式——用AOP测试业务层方法的执行时间
  14. ElasticSearch实战-编码实践
  15. 【CF827E】Rusty String 调和级数+FFT
  16. 部署和编写简单web项目
  17. JUC集合之 ConcurrentSkipListSet
  18. 推荐:普通UI设计师与顶级UI设计师的区别是什么?(转)
  19. sama5d36 OUT0-OUT3 对应关系 带光模块的系统
  20. poj 1724 ROADS 解题报告

热门文章

  1. window10系统安装Ubuntu18.04系统
  2. A. Pride (emmmm练习特判的好题)
  3. Java生成固定长度的随机字符串(以大小写字母和数字)
  4. Mac 安装和卸载 Mysql5.7.11 的方法
  5. 浏览器window产生的缓存九种解决办法
  6. Java中的线程--Lock和Condition实现线程同步通信
  7. clover如何使用UEFI引导和EFI驱动选择
  8. (17)zabbix自定义用户key与参数User parameters
  9. 主DNS服务-正向解析
  10. 阀值化 threshold