因为网上Dinic模板大多不规范或者可以被卡,所以先贴出一份跑得比较快的Dinic模板(主要快在maxflow()里面,可以仔细体会)。
struct newG{
int g[Maxn],v[Maxm],c[Maxm],nt[Maxm],cur[Maxn],lev[Maxn],ec;
queue<int>q;
inline void init(){memset(g,0,sizeof(g));ec=1;}
inline void add(int x,int y,int o){++ec;nt[ec]=g[x];g[x]=ec;v[ec]=y;c[ec]=o;}
inline bool bfs(){
while(!q.empty())q.pop();
for(int i=0;i<=n;i++)lev[i]=0;
q.push(src);lev[src]=1;
while(!q.empty()){
int u=q.front();q.pop();
for(int j=g[u];j;j=nt[j]){
if(!c[j]||lev[v[j]])continue;
lev[v[j]]=lev[u]+1;q.push(v[j]);
if(v[j]==des)return true;
}
}
return false;
}
inline int dinic(const int &now,int flow){
if(now==des)return flow;
int res=0;
for(int &j=cur[now];j;j=nt[j]){
if(!c[j]||(lev[v[j]]!=lev[now]+1))continue;
int o=dinic(v[j],min(flow-res,c[j]));
res+=o;c[j]-=o;c[j^1]+=o;
if(res==flow)return res;
}
return (lev[now]=0,res);
}
inline int maxflow(){
int ans=0;
while(bfs()){
int t;memcpy(cur,g,sizeof(int)*(n+1));
while(t=dinic(src,h),t){
ans+=t;memcpy(cur,g,sizeof(int)*(n+1));
}
}
return ans;
}
}g2;
(以下题意请自行百度)
###1.最优分配
####poj1149
应该是很裸的题了。
对于每个人直接从原来的猪舍连一条边,如果发现猪舍已经被其他人打开过了,那么其他人的作用相当于是合并了这几个猪舍,直接找到最后一个合并此猪舍的点连边即可。最后网络流跑一个类似最优分配的问题就行了。
####poj3281
先建立三排点,分别表示饮料,牛,食物。
注意对应的关系是牛对食物和饮料的,所以牛放在最中间。因为有限制(每头牛为1),所以拆一下点就好了。
####Joj2453
因为吉林大学OJ没有了,所以这道题暂时不能在线评测。
想了半天,最后看了题解恍然大悟:
显然糖果可以随意分配,但如果我把
A
i
A_i
Ai可以为2的糖果尽量多分配出去,其他的来填剩下的就好了,所以其实是一个最大匹配问题。
####WOJ 1124
同样也是不能在线评测。。
思路很简单,首先让与 n n n有关的比赛全赢,之后对于每个队到S点设置一个限制,然后尽量把与比赛之间的连边跑满就行了。
###2.二分
####poj2391
经典套路题。。
一种比较显然的建图方式是每个点新增一个点作为最终的牛棚点并向终点连一条有限制的边,然后原图每个点连向自己的牛棚。
可是有时间的限制。一开始我想跑费用流,可是最后发现无法把时间累加起来,这时候经典套路就出现了:二分时间限制连边。然后好像就做完了。。
####SGU438
加上了求最小的时间,同样是很经典的拆点做网络流,把每个点和时间一起看做一个点,此题依次加点就行了,也可以二分+网络流。
Code:http://paste.ubuntu.com/26110544/
####SPOJ287
首先按照题意建图跑网络流。
据说一种网络流方案需要的颜色的数量是最大的边的容量(这个我是真不会证明,哪位dalao证出来了麻烦给我说一下,感激不尽)。那么直接二分就行了。
(Dinic :5.3s ISAP : 8.0s)。
Code:http://paste.ubuntu.com/26111044/ (可以自测一下,两份代码都有)
##3.限制点边次数
####ZOJ2760
很自然的想到先保留每一条在最短路径上的边,并限制每条边容量为1。
####SGU 326
同上。
####SPOJ962
转化为从B出发找两条增广路即可。