(最小割)洛谷P1361 小M的作物

it2025-05-16  3

洛谷P1361 小M的作物

思路:

这是一个两者取一的模型,将点集一分为二。 最小割在数值上等同于最大流。割去权值和最小的边,使图分成两部分,割下来的边权值和为最小割。 对于此题,先不考虑种在一起的情况。对于种在 A , B A,B A,B两地分别能获得的 a i , b i a_i,b_i ai,bi的收益,我们可以考虑从 S S S i i i建一条边,权值为 a i a_i ai;从 i i i T T T建一条边,权值为 b i b_i bi。 那么种在一起获得额外收益可以建虚点 j 1 , j 2 j_1,j_2 j1,j2,由 S S S j 1 j_1 j1连边,权值为 c 1 i c_{1i} c1i, j 1 j_1 j1向集合中其他点连边,权值为 i n f inf inf;对于 c 2 i c_{2i} c2i同理 j 2 j_2 j2连向 T T T。权值为 i n f inf inf意味着不可割,我们只需要考虑 S − > j 1 , j 2 − > T S->j_1,j_2->T S>j1,j2>T会割哪条(全部)就行了。 这题数据比较大,要采用优化的dinic才行。

代码:

#include<bits/stdc++.h> #define pii pair<int,int> #define ll long long #define cl(x,y) memset(x,y,sizeof(x)) #define ct cerr<<"Time elapsed:"<<1.0*clock()/CLOCKS_PER_SEC<<"s.\n"; const int N=1e4+10; const int mod=1e9+7; const int maxn=0x3f3f3f3f; const int minn=0xc0c0c0c0; const int inf=99999999; using namespace std; struct edge { int u,v,w; }maze[4000000]; int len=1,head[N]={0},dep[N]; void add(int u,int v,int w) { maze[++len]={head[u],v,w}; head[u]=len; } int bfs(int s,int t) { queue<int> q; cl(dep,0); dep[s]=1; q.push(s); while(!q.empty()) { int u=q.front(),i; q.pop(); for(i=head[u];i;i=maze[i].u) { int v=maze[i].v,w=maze[i].w; if(w && !dep[v]) { dep[v]=dep[u]+1; q.push(v); } } } return dep[t]; } int dfs(int u,int f,int t) { int ans=0,i; if(u==t) return f; for(i=head[u];i && f;i=maze[i].u) { int v=maze[i].v,w=maze[i].w; if(dep[u]+1==dep[v] && w) { int sum=dfs(v,min(f,w),t); maze[i].w-=sum; maze[i^1].w+=sum; f-=sum; ans+=sum; } } if(!ans) dep[u]=-2; return ans; } int dinic(int s,int t) { int ans=0; while(bfs(s,t)) ans+=dfs(s,maxn,t); return ans; } signed main() { int n,m,i,x,s,t,sum=0; scanf("%d",&n); s=n+1; t=s+1; for(i=1;i<=n;i++) { scanf("%d",&x); sum+=x; add(s,i,x); add(i,s,0); } for(i=1;i<=n;i++) { scanf("%d",&x); sum+=x; add(i,t,x); add(t,i,0); } scanf("%d",&m); for(i=1;i<=m;i++) { int ca,j,a,b; scanf("%d%d%d",&ca,&a,&b); sum+=a+b; add(s,n+2+i,a); add(n+2+i,s,0); add(n+2+i+m,t,b); add(t,n+2+i+m,0); for(j=1;j<=ca;j++) { scanf("%d",&x); add(n+2+i,x,maxn); add(x,n+2+i,0); add(x,n+2+i+m,maxn); add(n+2+i+m,x,0); } } int flow=dinic(s,t); int res=sum-flow; printf("%d\n",res); return 0; }
最新回复(0)