zoukankan      html  css  js  c++  java
  • 【BZOJ】【1532】【POI2005】Kos-Dicing

    网络流/二分法


      最大值最小……直接做不太好做的时候就可以用二分+判定来搞。

      这题我们就也可以二分最大胜场v,那么怎么来判定呢?首先我们发现:每场比赛要么A赢,要么B赢,这一点跟二分图匹配非常类似,那么我们就可以建二分图:左部是参赛队伍,右边的结点表示每场比赛,对于第 i 场比赛:两支参赛队伍连x[i]->i+n和y[i]->i+n两条边,容量为1;连接i+n->T容量为1。对于第 j 支队伍,我们连S->j 容量为二分的最大胜场v。判定方法就是跑最大流,如果每场比赛都能分配出一个胜者(最大流=m)则当前v可行。

      1 /**************************************************************
      2     Problem: 1532
      3     User: Tunix
      4     Language: C++
      5     Result: Accepted
      6     Time:812 ms
      7     Memory:2976 kb
      8 ****************************************************************/
      9  
     10 //BZOJ 1532
     11 #include<vector>
     12 #include<cstdio>
     13 #include<cstring>
     14 #include<cstdlib>
     15 #include<iostream>
     16 #include<algorithm>
     17 #define rep(i,n) for(int i=0;i<n;++i)
     18 #define F(i,j,n) for(int i=j;i<=n;++i)
     19 #define D(i,j,n) for(int i=j;i>=n;--i)
     20 #define pb push_back
     21 using namespace std;
     22 inline int getint(){
     23     int v=0,sign=1; char ch=getchar();
     24     while(ch<'0'||ch>'9'){ if (ch=='-') sign=-1; ch=getchar();}
     25     while(ch>='0'&&ch<='9'){ v=v*10+ch-'0'; ch=getchar();}
     26     return v*sign;
     27 }
     28 const int N=20100,M=100010,INF=~0u>>2;
     29 typedef long long LL;
     30 /******************tamplate*********************/
     31 int n,m,tot,ans,x[N],y[N];
     32 struct edge{int to,v;};
     33 struct Net{
     34     edge E[M];
     35     int head[N],next[M],cnt;
     36     void ins(int x,int y,int v){
     37         E[++cnt]=(edge){y,v};
     38         next[cnt]=head[x]; head[x]=cnt;
     39     }
     40     void add(int x,int y,int v){
     41         ins(x,y,v); ins(y,x,0);
     42     }
     43     int s,t,cur[N],d[N],Q[N];
     44     bool mklevel(){
     45         memset(d,-1,sizeof d);
     46         d[s]=0;
     47         int l=0,r=-1;
     48         Q[++r]=s;
     49         while(l<=r){
     50             int x=Q[l++];
     51             for(int i=head[x];i;i=next[i])
     52                 if (d[E[i].to]==-1 && E[i].v){
     53                     d[E[i].to]=d[x]+1;
     54                     Q[++r]=E[i].to;
     55                 }
     56         }
     57         return d[t]!=-1;
     58     }
     59     int dfs(int x,int a){
     60         if (x==t) return a;
     61         int flow=0;
     62         for(int &i=cur[x];i && flow<a;i=next[i])
     63             if (E[i].v && d[E[i].to]==d[x]+1){
     64                 int f=dfs(E[i].to,min(a-flow,E[i].v));
     65                 E[i].v-=f;
     66                 E[i^1].v+=f;
     67                 flow+=f;
     68             }
     69         if (!flow) d[x]=-1;
     70         return flow;
     71     }
     72     void Dinic(){
     73         while(mklevel()){
     74             F(i,s,t) cur[i]=head[i];
     75             ans+=dfs(s,INF);
     76         }
     77     }
     78     void build(int v){
     79         cnt=1;ans=0;
     80         memset(head,0,sizeof head);
     81         F(i,1,n) add(s,i,v);
     82         F(i,1,m){
     83             add(i+n,t,1);
     84             add(x[i],i+n,1);
     85             add(y[i],i+n,1);
     86         }
     87     }
     88 }G1;
     89 int main(){
     90 #ifndef ONLINE_JUDGE
     91     freopen("1532.in","r",stdin);
     92     freopen("1532.out","w",stdout);
     93 #endif
     94     n=getint();m=getint();
     95     G1.s=0;G1.t=n+m+1;
     96     F(i,1,m) x[i]=getint(),y[i]=getint();
     97     int l=1,r=m;
     98     while(l<=r){
     99         int mid=l+r>>1;
    100         G1.build(mid);
    101         G1.Dinic();
    102         if (ans==m) r=mid-1;
    103         else l=mid+1;
    104     }
    105     printf("%d
    ",l);
    106     return 0;
    107 }
    View Code

    1532: [POI2005]Kos-Dicing

    Time Limit: 5 Sec  Memory Limit: 64 MB
    Submit: 1211  Solved: 382
    [Submit][Status][Discuss]

    Description

    Dicing 是一个两人玩的游戏,这个游戏在Byteotia非常流行. 甚至人们专门成立了这个游戏的一个俱乐部. 俱乐部的人时常在一起玩这个游戏然后评选出玩得最好的人.现在有一个非常不走运的家伙,他想成为那个玩的最好的人,他现在知道了所有比赛的安排,他想知 道,在最好的情况下,他最少只需要赢几场就可以赢得冠军,即他想知道比赛以后赢的最多的那个家伙最少会赢多少场.

    Input

    第一行两个整数n 和 m, 1 <= n <= 10 000, 0 <= m <= 10 000; n 表示一共有多少个参赛者, m 表示有多少场比赛. 选手从1 到 n编号. 接下来m 行每行两个整数表示该场比赛的两个选手,两个选手可能比赛多场.

    Output

    第一行表示赢得最多的人最少会赢多少场

    Sample Input

    4 4
    1 2
    1 3
    1 4
    1 2

    Sample Output

    1

    HINT

    Source

    [Submit][Status][Discuss]
  • 相关阅读:
    git初学【常用命令、上传项目到码云或从码云拉取、克隆项目】
    dedecms自学
    sublime3使用笔记
    路由功能
    bootstrap模态框篇【遇到的问题】
    justgage.js的使用
    fullpage.js使用方法
    js&jq遇到的问题(不断更新中)
    图灵完备——停机问题
    中断
  • 原文地址:https://www.cnblogs.com/Tunix/p/4338948.html
Copyright © 2011-2022 走看看