【最小割】BZOJ3438-小M的作物(Rank 2???!!!)(含新款Dinic模板)
一开始被T掉了之后,才害怕地发现之前写的Dinic基本上都是错的??!!!正确的写在注释里了,注意一下(;3<)馬鹿やろ
一个丧心病狂的优化前后效率对比:🐕
【题目大意】
有A、B两块地和n个农作物,每个农作物种在A可产生ai价值,种在B可产生bi价值。又存在m种组合,若组合里所有农作物均种在A可产生c1i价值,均种在B可产生c2i价值。问如何种价值最大?
【思路】
建立源点S和汇点T,代表A、B两块地。
对于某个农作物xi,由S向xi连容量为ai的边,由xi向T连容量为bi的边。
对于组合m,我们建立两个点y1i,y2i,由S向y1i连容量为c1i的边,由y2i向T连容量为c2i的边。由y1i向组合里的每个x连容量为INF的边,由组合里的每个x向y2i容量为INF的边。
(关于有人问会不会某个组合里的点有的种在了A,有的种在了B,不会呀,否则S到T就有一条通路了)
要求的就是最小割=最大流。答案=总价值-最小割。
Rank2了,天真地想一想如果加个读入优化,再加个当前弧优化,再不用STL,能不能Rank1呢
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<queue> 6 #include<vector> 7 #define S 0 8 #define T (m*2+n)+1 9 using namespace std; 10 const int MAXN=1000+50; 11 const int INF=0x7fffffff; 12 struct node 13 { 14 int to,pos,cap; 15 }; 16 int m,n; 17 vector<node> E[MAXN*3]; 18 int dis[MAXN*3],ans,a[MAXN],b[MAXN]; 19 20 void addedge(int u,int v,int w) 21 { 22 E[u].push_back((node){v,E[v].size(),w}); 23 E[v].push_back((node){u,E[u].size()-1,0}); 24 } 25 26 void init() 27 { 28 ans=0; 29 scanf("%d",&n); 30 for (int i=1;i<=n;i++) scanf("%d",&a[i]); 31 for (int i=1;i<=n;i++) scanf("%d",&b[i]); 32 scanf("%d",&m); 33 for (int i=1;i<=n;i++) 34 { 35 ans+=a[i]+b[i]; 36 addedge(S,i,a[i]); 37 addedge(i,T,b[i]); 38 } 39 int cnt=n; 40 for (int i=1;i<=m;i++) 41 { 42 int k,c1,c2,x; 43 scanf("%d%d%d",&k,&c1,&c2); 44 ++cnt,addedge(S,cnt,c1); 45 ++cnt,addedge(cnt,T,c2); 46 ans+=c1+c2; 47 for (int j=0;j<k;j++) 48 { 49 scanf("%d",&x); 50 addedge(cnt-1,x,INF); 51 addedge(x,cnt,INF); 52 } 53 } 54 } 55 56 bool bfs() 57 { 58 memset(dis,-1,sizeof(dis)); 59 queue<int> que; 60 while (!que.empty()) que.pop(); 61 que.push(S); 62 dis[S]=0; 63 while (!que.empty()) 64 { 65 int head=que.front();que.pop(); 66 if (head==T) return true; //首次抵达T即可返回,不需要整张图全部分层 67 for (int i=0;i<E[head].size();i++) 68 { 69 node tmp=E[head][i]; 70 if (dis[tmp.to]==-1 && tmp.cap) 71 { 72 dis[tmp.to]=dis[head]+1; 73 que.push(tmp.to); 74 } 75 } 76 } 77 return false; 78 } 79 80 int dfs(int s,int e,int f) 81 { 82 if (s==e) return f; 83 int ret=0; 84 for (int i=0;i<E[s].size();i++) 85 { 86 node &tmp=E[s][i]; 87 if (dis[tmp.to]==dis[s]+1 && tmp.cap) 88 { 89 int delta=dfs(tmp.to,e,min(f,tmp.cap)); 90 if (delta>0) 91 { 92 tmp.cap-=delta; 93 E[tmp.to][tmp.pos].cap+=delta; 94 f-=delta; 95 ret+=delta; 96 if (f==0) return ret; 97 } 98 else dis[tmp.to]=-1;//注意一下这里要清为-1,很重要★★★★★ 99 } 100 } 101 return ret; 102 } 103 104 void dinic() 105 { 106 while (bfs()) 107 { 108 int f=dfs(S,T,INF); 109 if (f) ans-=f;else break; 110 } 111 printf("%d\n",ans); 112 } 113 114 int main() 115 { 116 init(); 117 dinic(); 118 return 0; 119 }
---提炼一个Dinic模板出来--
1 bool bfs() 2 { 3 memset(dis,-1,sizeof(dis)); 4 queue<int> que; 5 while (!que.empty()) que.pop(); 6 que.push(S); 7 dis[S]=0; 8 while (!que.empty()) 9 { 10 int head=que.front();que.pop(); 11 if (head==T) return true; //首次抵达T即可返回,不需要整张图全部分层 12 for (int i=0;i<E[head].size();i++) 13 { 14 node tmp=E[head][i]; 15 if (dis[tmp.to]==-1 && tmp.cap)16 { 17 dis[tmp.to]=dis[head]+1; 18 que.push(tmp.to); 19 } 20 } 21 } 22 return false; 23 } 24 25 int dfs(int s,int e,int f) 26 { 27 if (s==e) return f; 28 int ret=0; 29 for (int i=0;i<E[s].size();i++) 30 { 31 node &tmp=E[s][i]; 32 if (dis[tmp.to]==dis[s]+1 && tmp.cap) 33 { 34 int delta=dfs(tmp.to,e,min(f,tmp.cap)); 35 if (delta>0) 36 { 37 tmp.cap-=delta; 38 E[tmp.to][tmp.pos].cap+=delta; 39 f-=delta; 40 ret+=delta; 41 if (f==0) return ret; 42 } 43 else dis[tmp.to]=-1;//注意一下这里要清为-1,很重要★★★★★ 44 } 45 } 46 return ret; 47 } 48 49 void dinic() 50 { 51 int flow=0; 52 while (bfs()) 53 { 54 int f=dfs(S,T,INF); 55 if (f) flow+=f;else break; 56 } 57 printf("%d\n",flow); 58 }