N个盒子围成一圈,第i个盒子初始时有Ai个小球,每次可以把一个小球从一个盒子移到相邻的两个盒子之一里。问最少移动多少次使得每个盒子中小球的个数不超过1。
ΣAi<=N.1<=N<=1000.
最小费用最大流。
每个盒子作为一个点。
若Ai>1则从源点向此点连一条容量为Ai,费用为0的边。
若Ai=0则从此点向汇点连一条容量为1,费用为0的边。
每个盒子向相邻的两个盒子连容量为正无穷,费用为1的边。
最小费用最大流即为答案。
1 #include<cstring> 2 #include<cstdio> 3 #include<iostream> 4 #include<algorithm> 5 #include<queue> 6 using namespace std; 7 const int dian=1005; 8 const int bian=6005; 9 const int INF=0x3f3f3f3f; 10 int h[dian],nxt[bian],ver[bian],val[bian],cos[bian],with[dian],minn[dian]; 11 int d[dian],v[dian]; 12 int map[dian]; 13 int n,tot; 14 int S,T; 15 void add(int a,int b,int c,int d){ 16 tot++;ver[tot]=b;val[tot]=c;cos[tot]=d;nxt[tot]=h[a];h[a]=tot; 17 tot++;ver[tot]=a;val[tot]=0;cos[tot]=-d;nxt[tot]=h[b];h[b]=tot; 18 } 19 bool tell(){ 20 memset(v,0,sizeof(v)); 21 memset(d,0x3f,sizeof(d)); 22 memset(with,0,sizeof(with)); 23 memset(minn,0x3f,sizeof(minn)); 24 queue<int>q; 25 q.push(S); 26 v[S]=1; 27 d[S]=0; 28 while(!q.empty()){ 29 int x=q.front(); 30 q.pop(); 31 v[x]=0; 32 for(int i=h[x];i;i=nxt[i]){ 33 int y=ver[i]; 34 if(d[y]>d[x]+cos[i]&&val[i]){ 35 d[y]=d[x]+cos[i]; 36 minn[y]=min(minn[x],val[i]); 37 with[y]=i; 38 if(!v[y]){ 39 v[y]=1; 40 q.push(y); 41 } 42 } 43 } 44 } 45 if(d[T]==0x3f3f3f3f) 46 return 0; 47 return 1; 48 } 49 int zeng(){ 50 for(int i=T;i!=S;i=ver[with[i]^1]){ 51 val[with[i]]-=minn[T]; 52 val[with[i]^1]+=minn[T]; 53 } 54 return minn[T]*d[T]; 55 } 56 int dinic_cost(){ 57 int r=0; 58 while(tell()) 59 r+=zeng(); 60 return r; 61 } 62 int main(){ 63 int cas; 64 scanf("%d",&cas); 65 while(cas--){ 66 memset(h,0,sizeof(h)); 67 memset(nxt,0,sizeof(nxt)); 68 tot=1; 69 scanf("%d",&n); 70 S=n+1,T=n+2; 71 for(int i=1;i<=n;i++) 72 scanf("%d",&map[i]); 73 for(int i=1;i<=n;i++){ 74 if(map[i]>1) 75 add(S,i,map[i]-1,0); 76 else if(!map[i]) 77 add(i,T,1,0); 78 add(i,(i==1)?n:i-1,INF,1); 79 add(i,(i==n)?1:i+1,INF,1); 80 } 81 printf("%d\n",dinic_cost()); 82 } 83 return 0; 84 }
时间: 2024-10-11 08:36:15