1. 程式人生 > >【BZOJ 2673】[Wf2011]Chips Challenge

【BZOJ 2673】[Wf2011]Chips Challenge

斷流 ble min label back 棋盤 problem else get

題目大意:

  傳送門

  $n*n$的棋盤,有一些位置可以放棋子,有一些已經放了棋子,有一些什麽都沒有,也不能放,要求放置以後滿足:第i行和第i列的棋子數相同,同時每行的棋子數占總數比例小於$\frac{A}{B}$。求最多可以放多少,無解則輸出$impossible$。

題解:

  Orz一發大佬——傳送門。

  先把整張圖放滿,題目就轉化為最少刪多少點就合法。

  我們用$numx$來記錄每行可以放的和已經放棋子總數,$numy$記錄每列。從$S$向第i行連流量為$numx_i$的0費用邊,從第j列向$T$連流量為$numy_j$的邊。先不考慮怎麽構建中間的圖,在不考慮$\frac{A}{B}$的情況,我們需要判斷流量合法的,我們可以讓到$T$的邊都滿流意味著選了和沒選的可以構成全集。

  我們對於可以放棋子的地方$(x,y)$,由第$x$行到第$y$列連$flow=1,cost=1$的邊,表示將這個點刪去的所需價值。

  考慮後一個限制。

  我們可以枚舉每一行最多放置的棋子個數$f$,然後我們從第$i$行向第$i$列連一條$flow=f,cost=0$的邊。表示第i行選了最多保留$f$個棋子,第$i$列保留棋子等同於這條邊的流量,因為其他連向第$i$列的邊都是要費用的,對第$i$行來講其他的出邊也是要費用的,而那些要費用的邊就是刪去的集合。

  然後判斷一下當前解是否合法即可。

代碼:

  1 #include "bits/stdc++.h"
  2 
  3
using namespace std; 4 5 #define inf 0x3f3f3f3f 6 7 inline int read() { 8 int s=0,k=1;char ch=getchar (); 9 while (ch<0|ch>9) ch==-?k=-1:0,ch=getchar(); 10 while (ch>47&ch<=9) s=s*10+(ch^48),ch=getchar(); 11 return s*k; 12 } 13 14 const
int N=100; 15 16 struct edges { 17 int v,cap,cost;edges *pair,*last; 18 }edge[N*N],*head[N];int cnt; 19 20 inline void push(int u,int v,int cap,int cost) { 21 edge[++cnt]=(edges){v,cap,cost,edge+cnt+1,head[u]},head[u]=edge+cnt; 22 edge[++cnt]=(edges){u,0,-cost,edge+cnt-1,head[v]},head[v]=edge+cnt; 23 } 24 25 int S,T,n,fl,ans; 26 int piS,vis[N]; 27 int cost; 28 29 inline int aug(int x,int w) { 30 if (x==T) return cost+=1ll*piS*w,fl+=w,w; 31 vis[x]=true; 32 int ret=0; 33 for (edges *i=head[x];i;i=i->last) 34 if (i->cap&&!i->cost&&!vis[i->v]) { 35 int flow=aug(i->v,min(i->cap,w)); 36 i->cap-=flow,i->pair->cap+=flow,ret+=flow,w-=flow; 37 if (!w) break; 38 } 39 return ret; 40 } 41 42 inline bool modlabel() { 43 static int d[N]; 44 memset(d,0x3f,sizeof d);d[T]=0; 45 static deque<int> q;q.push_back(T); 46 int dt; 47 while (!q.empty()) { 48 int x=q.front();q.pop_front(); 49 for (edges *i=head[x];i;i=i->last) 50 if (i->pair->cap&&(dt=d[x]-i->cost)<d[i->v]) 51 (d[i->v]=dt)<=d[q.size()?q.front():0] 52 ?q.push_front(i->v):q.push_back(i->v); 53 } 54 for (int i=S;i<=T;++i) 55 for (edges *j=head[i];j;j=j->last) 56 j->cost+=d[j->v]-d[i]; 57 piS+=d[S]; 58 return d[S]<inf; 59 } 60 61 inline void solve() { 62 piS = cost = 0; 63 while(modlabel()) 64 do memset(vis,0,sizeof vis); 65 while(aug(S, inf)); 66 } 67 68 char mp[N][N]; 69 int numx[N],numy[N],A,B; 70 71 int main() { 72 n=read(),A=read(),B=read(); 73 T=n<<1|1; 74 int used=0,sum=0; 75 ans=-1; 76 for (int i=1;i<=n;++i) { 77 scanf("%s",mp[i]+1); 78 for (int j=1;j<=n;++j) 79 if(mp[i][j]==C||mp[i][j]==.) { 80 ++sum,++numx[i],++numy[j]; 81 used+=mp[i][j]==C; 82 } 83 } 84 for (int flow=0;flow<=n;++flow) { 85 memset(head,0,sizeof head); 86 cnt=0;fl=0; 87 for (int i=1;i<=n;++i) { 88 push(S,i,numx[i],0); 89 push(i+n,T,numy[i],0); 90 push(i,i+n,flow,0); 91 for (int j=1;j<=n;++j) 92 if(mp[i][j]==.) 93 push(i,j+n,1,1); 94 } 95 solve(); 96 if (fl==sum&&flow*B<=(sum-cost)*A) 97 ans=max(ans,sum-cost); 98 } 99 if (ans==-1) puts("impossible"); 100 else printf("%d\n",ans-used); 101 }

【BZOJ 2673】[Wf2011]Chips Challenge