bzoj 3961: [WF2011]Chips Challenge【最小费用最大流】
2018-04-24 11:06
302 查看
参考:https://www.geek-share.com/detail/2664346702.html
神建图系列
首先把问题转为全填上,最少扣下来几个能符合条件
先考虑第2个条件,枚举f为一个每行/列最大剩几个,然后记录一下每行列的零件个数(包括填上的)
然后建图
s向所有行连流量为这行的零件数的边,所有列向t连流量为这列的零件数的边,i行向i列连流量为f的边,表示这行列最多流f,每个能扣下来的(i,j)连i行j列,因为这个要尽量小而且需要计数,所以附加上1的价值(别的边都为0),然后跑最小费用最大流,判合法有两个条件:1,总流量为总零件数(满流),因为选和不选都能在图上流过去;2,fb<=(sum-val)a
以及我之前写的费用流板子都是错的???
而且这个好像不能动态加流量,只能枚举着重建图。
#include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; const int N=105,inf=1e9; int n,a,b,h ,cnt,s,t,flo,val,dis ,fr ; char p ; bool v ,vis ; struct qwe { int ne,no,to,va,c; }e[N*N]; void add(int u,int v,int w,int c) { cnt++; e[cnt].ne=h[u]; e[cnt].no=u; e[cnt].to=v; e[cnt].va=w; e[cnt].c=c; h[u]=cnt; } void ins(int u,int v,int w,int c) {//cerr<<u<<" "<<v<<" "<<w<<" "<<c<<endl; add(u,v,w,c); add(v,u,0,-c); } bool spfa() { memset(v,0,sizeof(v)); queue<int>q; for(int i=s;i<=t;i++) dis[i]=inf; dis[s]=0; v[s]=1; q.push(s); while(!q.empty()) { int u=q.front();//cerr<<u<<endl q.pop(); v[u]=0; for(int i=h[u];i;i=e[i].ne) if(e[i].va>0&&dis[e[i].to]>dis[u]+e[i].c) { dis[e[i].to]=dis[u]+e[i].c; fr[e[i].to]=i; if(!v[e[i].to]) v[e[i].to]=1,q.push(e[i].to); } } return dis[t]!=inf; } // void mcf() // { // int x=inf; // for(int i=fr[t];i;i=fr[e[i].no]) // x=min(x,e[i].va);//,cerr<<e[i].to<<" ";cerr<<endl; // flo+=x; // for(int i=fr[t];i;i=fr[e[i].no]) // { // e[i].va-=x; // e[i^1].va+=x; // val+=x*e[i].c; // } // } inline int dfs(int u,int f) { if(u==t) return f; int us=0; vis[u]=1; for(int i=h[u];i&&us<f;i=e[i].ne) if(e[i].va>0&&!vis[e[i].to]&&dis[e[i].to]==dis[u]+e[i].c) { int t=dfs(e[i].to,min(f,e[i].va)); us+=t; val+=e[i].c*t , e[i].va-=t,e[i^1].va+=t; } if(!us) dis[u]=inf; vis[u]=0; return us; } int main() { for(int cas=1;;cas++) { scanf("%d%d%d",&n,&a,&b); if(n+a+b==0) break; int sum=0,con=0,r[45],c[45],ans=-1; cnt=1,s=0,t=2*n+1,flo=0,val=0; memset(h,0,sizeof(h)); memset(r,0,sizeof(r)); memset(c,0,sizeof(c)); for(int i=1;i<=n;i++) { scanf("%s",p[i]+1); for(int j=1;j<=n;j++) if(p[i][j]!='/') { sum++,r[i]++,c[j]++; if(p[i][j]=='C') con++; // else // ins(i,j+n,1,1); } } // for(int i=1;i<=n;i++) // ins(s,i,r[i],0),ins(i+n,t,c[i],0); // int st=cnt+1; // for(int i=1;i<=n;i++) // ins(i,i+n,0,0); // while(spfa()) // mcf(); //cerr<<flo<<" "<<val<<endl; // if(flo==sum&&(sum-val)*a>=0) // ans=max(ans,sum-val); // for(int f=1;f<=n;f++) // { // for(int i=st;i<=cnt;i+=2) // e[i].va++; // while(spfa()) // mcf(); // cerr<<flo<<" "<<val<<endl; // if(flo==sum&&(sum-val)*a>=f*b) // ans=max(ans,sum-val); // } for(int f=0;f<=n;++f) { memset(h,0,sizeof h); flo=val=s=0;cnt=1; t=n*2+1; for(int i=1;i<=n;++i) { ins(s,i,r[i],0); ins(i+n,t,c[i],0); ins(i,i+n,f,0); for(int j=1;j<=n;++j) if(p[i][j]=='.') ins(i,j+n,1,1); } while(spfa()) flo+=dfs(s,inf); if(flo==sum&&f*b<=(sum-val)*a) ans=max(ans,sum-val); } printf("Case %d: ",cas); if(ans==-1) puts("impossible"); else printf("%d\n",ans-con); } return 0; } /* 2 1 1 /. // 2 50 100 /. C/ 0 0 0 */
相关文章推荐
- BZOJ 2324: [ZJOI2011]营救皮卡丘(带上下限的最小费用最大流)
- 【BZOJ3963】【ACM-WF2011】MachineWorks(CDQ分治+斜率优化)
- 【BZOJ3693】【WF2011】MachineWorks
- bzoj3963[WF2011]MachineWorks cdq分治+斜率优化dp
- [BZOJ3958][WF2011]Mummy Madness(二分+扫描线+线段树)
- bzoj 2245 [SDOI2011]工作安排(最小费用最大流)
- BZOJ_3963_[WF2011]MachineWorks_斜率优化+CDQ分治
- [BZOJ2324][ZJOI2011]营救皮卡丘(最小费用最大流)
- [BZOJ3963][WF2011][CDQ分治][斜率优化][DP]MachineWorks
- [BZOJ 3963][WF2011]MachineWorks:CDQ分治|DP斜率优化
- ●BZOJ 3963 [WF2011]MachineWorks
- [BZOJ2324][ZJOI2011][最小费用最大流]营救皮卡丘
- [BZOJ2324][ZJOI2011][最小费用最大流]营救皮卡丘
- 【BZOJ 3958】 3958: [WF2011]Mummy Madness (二分+扫描线、线段树)
- BZOJ 3958: [WF2011]Mummy Madness
- 【BZOJ3963】[WF2011]MachineWorks cdq分治+斜率优化
- bzoj 3965: [WF2011]Pyramids
- bzoj 3963: [WF2011]MachineWorks (DP+CDQ分治)
- [BZOJ3963][WF2011]MachineWorks(斜率优化dp+cdq分治)
- bzoj 2245 [SDOI2011]工作安排【最小费用最大流】