bzoj1305 跳舞

  跳舞

题目背景:

bzoj1305

分析: 我们考虑这道题,我想应该还是能够比较容易的发现这是一道网络流,不论是题面推理,还是从数据范围来看,但是要是真的有这么的简单,那就显得不太正常了······我们考虑这么一个问题,我们可以考虑如果当前最多能跳a首曲子,那么我们可以向每一个点连一条容量为a的边,然后为了方便的处理,我们

1)将每一个人拆成两个点,男孩的两个点为X1X2,女孩为Y1Y2

2)将相互喜欢的每一对的X1Y1相连,互相讨厌的将X2Y2相连

3)然后从每一个X1X2连一条容量为k的边,每一个Y2Y1连一条容量为k的边

4)从原点向每一个X1连容量a的边,从每一个Y1向汇点连容量为a的边,

然后如果我们发现最终的结果是max_flow = n * a则说明可以满足a,那么我们可以发现a是单调的,即对于一个a如果满足,那么显然的a – 1也一定能够满足那么我们就可以根据这个性质进行二分,从而判断最大的能满流的a即可。

Source

#include 
   
   
    
    
#include 
    
    
     
     
#include 
     
     
      
      
#include 
      
      
       
       
#include 
       
       
         #include 
        
          #include 
         
           #include 
          
            #include 
           
             using namespace std; inline char read() { static const int IN_LEN = 1024 * 1024; static char buf[IN_LEN], *s, *t; if (s == t) { t = (s = buf) + fread(buf, 1, IN_LEN, stdin); if (s == t) return -1; } return *s++; } template 
            
              inline bool R(T &x) { static bool iosig; static char c; for (c = read(), iosig = false; !isdigit(c); c = read()) { if (c == -1) return false; if (c == '-') iosig = true; } for (x = 0; isdigit(c); c = read()) x = (x << 3) + (x << 1) + (c ^ '0'); if (iosig) x = -x; return true; } const int OUT_LEN = 1024 * 1024; char obuf[OUT_LEN], *oh = obuf; inline void writechar(char c) { if (oh == obuf + OUT_LEN) fwrite(obuf, 1, OUT_LEN, stdout), oh = obuf; *oh++ = c; } template 
             
               inline void W(T x) { static int buf[30], cnt; if (!x) writechar(48); else { if (x < 0) writechar('-'), x = -x; for (cnt = 0; x; x /= 10) buf[++cnt] = x % 10 + 48; while (cnt) writechar(buf[cnt--]); } } inline void flush() { fwrite(obuf, 1, oh - obuf, stdout); } const int MAXN = 200 + 20; const int INF = ~0u >> 1; int n, k, s, t; char c; int first[MAXN], temp[MAXN], dis[MAXN], gap[MAXN], ans[MAXN]; char map[MAXN][MAXN]; struct node { int to, w, f, rev; node(int to, int w, int rev) : f(0), to(to), w(w), rev(rev) {} }; vector 
              
                edge[MAXN]; inline void create(int x, int y, int z) { edge[x].push_back(node(y, z, edge[y].size())); edge[y].push_back(node(x, 0, edge[x].size() - 1)); } inline int boy1(int i) { return i;} //X1 inline int boy2(int i) { return n + i; } //X2 inline int girl1(int i) { return n * 2 + i; } //Y1 inline int girl2(int i) { return n * 3 + i; } //Y2 inline void readin() { cin >> n >> k; s = 0, t = 4 * n + 1; for (int i = 1; i <= n; ++i) for (int j = 1; j <= n; ++j) cin >> map[i][j]; } inline void buildgraph(int mid) { /*每一次根据二分所得的值进行二分*/ for (int i = s; i <= t; ++i) edge[i].clear(); for (int i = 1; i <= n; ++i) for (int j = 1; j <= n; ++j) { if (map[i][j] == 'Y') create(boy1(i), girl1(j), 1); else create(boy2(i), girl2(j), 1); } for (int i = 1; i <= n; ++i) { create(boy1(i), boy2(i), k), create(girl2(i), girl1(i), k); create(s, boy1(i), mid), create(girl1(i), t, mid); } } inline void bfs(int s, int t) { /*isap初始化 & bfs*/ memset(dis, -1, (t + 3 << 2)); memset(gap, 0, (t + 3 << 2)); memset(temp, 0, (t + 3 << 2)); queue 
               
                 q; q.push(t), dis[t] = 0, gap[0] = 1; while (!q.empty()) { int j = q.front(); q.pop(); for (int p = 0; p < edge[j].size(); ++p) { node &e = edge[j][p]; if (dis[e.to] == -1 && edge[e.to][e.rev].w > edge[e.to][e.rev].f) dis[e.to] = dis[j] + 1, q.push(e.to), gap[dis[e.to]]++; } } } inline int isap(int s, int t, int n) { static int stack[MAXN][2]; bfs(s, t); int cur = s, top = 0, flow = 0; while (dis[s] < n) { if (cur == t) { int minn = INF, pos; for (int i = 0; i < top; ++i) { node &e = edge[stack[i][0]][stack[i][1]]; if (minn > e.w - e.f) minn = e.w - e.f, pos = i; } for (int i = 0; i < top; ++i) { node &e = edge[stack[i][0]][stack[i][1]]; e.f += minn, edge[e.to][e.rev].f -= minn; } flow += minn, top = pos, cur = stack[pos][0]; continue; } bool valid = false; for (int p = temp[cur]; p < edge[cur].size(); ++p) { node &e = edge[cur][p]; if (dis[e.to] == dis[cur] - 1 && e.w > e.f) { valid = true, temp[cur] = p; break; } } if (valid) { stack[top][0] = cur, stack[top++][1] = temp[cur], cur = edge[cur][temp[cur]].to; continue; } int m = n - 1; for (int p = 0; p < edge[cur].size(); ++p) { node &e = edge[cur][p]; if (dis[e.to] < m && e.w > e.f) m = dis[e.to], temp[cur] = p; } if (--gap[dis[cur]] == 0) break; dis[cur] = m + 1, gap[dis[cur]]++; if (cur != s) cur = stack[--top][0]; } return flow; } inline void get() { /*二分获得最大值*/ int l = 0, r = n + 2; while (l + 1 < r) { int mid = l + r >> 1; buildgraph(mid); if (isap(s, t, t + 1) >= mid * n) l = mid; else r = mid; } cout << l; } int main() { //freopen("dance.in", "r", stdin); //freopen("dance.out", "w", stdout); readin(); get(); return 0; } 
                
               
              
             
            
           
          
         
       
      
      
     
     
    
    
   
   

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值