先缩点,然后拆点,其实是很经典的一种操作,把不好做的点拆成边,然后我一开始想的是网络流,答案当然是增广次数,

但可以发现跑网络流的话不同的跑法增广次数不一样,不太好找最小的。我们可以换一种神奇的思路,跑最大费用流,

这样根据费用流每次都在最长路上增广保证每次都跑了尽量多的点,根据贪心原理可知这样是正确的。

详见http://blog.csdn.net/iamzky/article/details/41846687;

(一开始我一直错,发现自己增广用的dinic,模板打惯了就直接打上了。。。。忘了dinic是可以一次dfs实现多次增广的,没法统计增广次数。。我好蠢啊)

#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
const int maxn=,inf=1e9;
struct edg{
int nxt,to,f,c;
}e[maxn],g[maxn];
int res,last[maxn],H[maxn],t1=,t2=,cas,dis[maxn],q[maxn],head,tail;
void add1(int x,int y){
++t1;e[t1].nxt=last[x];last[x]=t1;e[t1].to=y;
}
void add2(int x,int y,int z,int zz){
++t2;g[t2].nxt=H[x];H[x]=t2;g[t2].to=y;g[t2].f=z;g[t2].c=zz;
++t2;g[t2].nxt=H[y];H[y]=t2;g[t2].to=x;g[t2].f=;g[t2].c=-zz;
}
int scc,low[maxn],dfn[maxn],bel[maxn],cnt,sta[maxn],top,in[maxn];
void tarjan(int x){
low[x]=dfn[x]=++cnt;sta[++top]=x;in[x]=;
for(int i=last[x];i;i=e[i].nxt){
int v=e[i].to;
if(!dfn[v]){
tarjan(v);low[x]=min(low[x],low[v]);
}
else{
if(in[v])low[x]=min(low[x],dfn[v]);
} }
//cout<<"orz"<<endl;
if(low[x]==dfn[x]){
int now=;scc++;
while(now!=x){
now=sta[top--];in[now]=;
bel[now]=scc;
}
}
}
struct dui{
int from,to;
}tmp[maxn];
int pe[maxn],pv[maxn],mp[][],ans,vis[maxn],N,n,m,a,b,x,y,S,T,A[maxn],B[maxn],a1[maxn],b1[maxn];
void solve(){
while(){
memset(dis,-,sizeof(dis));
head=tail=;q[++tail]=S;dis[S]=;vis[S]=;
while(head!=tail){
head=(head+)%maxn;
int u=q[head];
for(int i=H[u];i;i=g[i].nxt){
int v=g[i].to;
if(g[i].f&&dis[v]<dis[u]+g[i].c){
dis[v]=dis[u]+g[i].c;
pe[v]=i;pv[v]=u;
if(!vis[v]){
vis[v]=;tail=(tail+)%maxn;
q[tail]=v;
}
}
}
vis[u]=;
}
if(dis[T]<)break;
int mm=inf;
for(int u=T;u!=S;u=pv[u])
mm=min(mm,g[pe[u]].f);
for(int u=T;u!=S;u=pv[u])
g[pe[u]].f-=mm,g[pe[u]^].f+=mm;
res+=dis[T]*mm;
if(dis[T]>)
++ans;
}
}
int main(){
cin>>cas;
while(cas--){
memset(mp,,sizeof(mp));
memset(last,,sizeof(last));
memset(H,,sizeof(H));
memset(dfn,,sizeof(dfn));
cin>>n>>m>>a>>b;
t1=t2=;scc=cnt=;
for(int i=;i<=a;++i){scanf("%d",&A[i]);}
for(int i=;i<=b;++i)scanf("%d",&B[i]);
for(int i=;i<=m;++i){
scanf("%d%d",&tmp[i].from,&tmp[i].to);
add1(tmp[i].from,tmp[i].to);
}
for(int i=;i<=n;++i){
if(!dfn[i])tarjan(i);
}
S=;T=scc*+;
for(int i=;i<=n;++i){
for(int j=last[i];j;j=e[j].nxt){
int u=bel[i],v=bel[e[j].to];
if(mp[u][v]||u==v)continue;
add2(u+scc+,v+,inf,);
mp[u][v]=mp[v][u]=;
}
}
for(int i=;i<=a;++i){
add2(S,+bel[A[i]],inf,);
}
for(int i=;i<=b;++i){
add2(+bel[B[i]]+scc,T,inf,);
}
for(int i=;i<=scc;++i){
add2(+i,+scc+i,,);add2(+i,+scc+i,inf,);
}
res=ans=;solve();
if(res!=scc)puts("no solution");
else{printf("%d\n",ans);}
}
//system("pause");
return ;
}

bzoj2893(费用流)的更多相关文章

  1. hdu-5988 Coding Contest(费用流)

    题目链接: Coding Contest Time Limit: 2000/1000 MS (Java/Others)     Memory Limit: 65536/65536 K (Java/Ot ...

  2. POJ2195 Going Home[费用流|二分图最大权匹配]

    Going Home Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 22088   Accepted: 11155 Desc ...

  3. BZOJ3130: [Sdoi2013]费用流[最大流 实数二分]

    3130: [Sdoi2013]费用流 Time Limit: 10 Sec  Memory Limit: 128 MBSec  Special JudgeSubmit: 960  Solved: 5 ...

  4. 洛谷 1004 dp或最大费用流

    思路: dp方法: 设dp[i][j][k][l]为两条没有交叉的路径分别走到(i,j)和(k,l)处最大价值. 则转移方程为 dp[i][j][k][l]=max(dp[i-1][j][k-1][l ...

  5. Codeforces 730I [费用流]

    /* 不要低头,不要放弃,不要气馁,不要慌张 题意: 给两行n个数,要求从第一行选取a个数,第二行选取b个数使得这些数加起来和最大. 限制条件是第一行选取了某个数的条件下,第二行不能选取对应位置的数. ...

  6. zkw费用流+当前弧优化

    zkw费用流+当前弧优化 var o,v:..] of boolean; f,s,d,dis:..] of longint; next,p,c,w:..] of longint; i,j,k,l,y, ...

  7. 【BZOJ-4213】贪吃蛇 有上下界的费用流

    4213: 贪吃蛇 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 58  Solved: 24[Submit][Status][Discuss] Desc ...

  8. 【BZOJ-3638&3272&3267&3502】k-Maximum Subsequence Sum 费用流构图 + 线段树手动增广

    3638: Cf172 k-Maximum Subsequence Sum Time Limit: 50 Sec  Memory Limit: 256 MBSubmit: 174  Solved: 9 ...

  9. [bzoj4514]数字配对[费用流]

    今年SDOI的题,看到他们在做,看到过了一百多个人,然后就被虐惨啦... 果然考试的时候还是打不了高端算法,调了...几天 默默地yy了一个费用流构图: 源连所有点,配对的点连啊,所有点连汇... 后 ...

随机推荐

  1. 半吊子的STM32 — SPI通信

    全双工,同步串行通信. 一般需要三条线通信: MOSI 主设备发送,从设备接收 MISO 主设备接收,从设备发送 SCLK 时钟线 多设备时,多线选取从机: 传输过程中,主从机中的移位寄存器中数据相互 ...

  2. sql like 语句

    a like '%b%'的意思是,在a中找类似b的字符,在检索以逗号分隔的字段中时,两次弄反了顺序,比如,在a字段中查找有没有类似‘2,3’的记录,应该这么写:','+'2,3' like '%,'+ ...

  3. (转)Silverlight调用的JS方法返回对象数组的处理方法

    最近在做Silverlight应用,需要用Silverlight调用页面中Javascript方法.这 个JS方法返回一个对象数组给Silverlight.对于这个对象数组怎么在Silverlight ...

  4. andorid 数据储存

    .xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android ...

  5. poj 3279 Fliptile(二进制)

    http://poj.org/problem?id=3279 在n*N的矩阵上,0代表白色,1代表黑色,每次选取一个点可以其颜色换过来,即白色变成黑色,黑色变成白色,而且其上下左右的点颜色也要交换,求 ...

  6. poj 3624 && hdu 2955(背包入门)

    http://poj.org/problem?id=3624 背包中最基础的01背包,大意是有N件物品和一个容量为V的背包.第i件物品的费用是c[i],价值是w[i].求解将哪些物品装入背包可使价值总 ...

  7. Go语言之讲解GOROOT、GOPATH、GOBIN

    Go是一门全新的静态类型开发语言,具有自动垃圾回收,丰富的内置类型,函数多返回值,错误处理,匿名函数,并发编程,反射等特性. go命令依赖一个重要的环境变量:$GOPATH GOPATH允许多个目录, ...

  8. contenteditable设置元素可编辑

    需求背景 实现一个输入框,高度可以随着输入文字的增加而自动增高 有placeholder,输入为空时,显示placeholder 我们知道可以将div的contenteditable设置伪true,将 ...

  9. Ajax在jQuery中的应用 (4)向jsp提交表单数据

    ajax技术带给我们的是良好的用户体验,同时,使用jquery可以简化开发,提高工作效率. 下面就介绍一下大致的开发步骤. 工具/原料 本文中使用的是 jquery-1.3.2.min.js 方法/步 ...

  10. Windows8 App Store 开发者会关心的文档

    在远程计算机上从 Visual Studio 调试和测试 Windows 应用商店应用程序 http://msdn.microsoft.com/zh-cn/library/windows/apps/h ...