zoukankan      html  css  js  c++  java
  • 【BZOJ 2673】[Wf2011]Chips Challenge

    题目大意:

      传送门

      $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
    ",ans-used);
    101 }
  • 相关阅读:
    systemd 介绍
    Goland读取配置文件--viper包
    Goland日志记录
    进程查询端口占用
    Python zip() 函数
    Jenkins权限管理(角色权限)
    Django ORM查询总结
    如何查看windows计算机重启记录
    Django ORM迁移
    Django中文乱码解决
  • 原文地址:https://www.cnblogs.com/Troywar/p/8847689.html
Copyright © 2011-2022 走看看