• ACM-ICPC 2018 沈阳赛区网络预赛 F. Fantastic Graph (贪心或有源汇上下界网络流)


    "Oh, There is a bipartite graph.""Make it Fantastic."
    X wants to check whether a bipartite graph is a fantastic graph. He has two fantastic numbers, and he wants to let all the degrees to between the two boundaries. You can pick up several edges from the current graph and try to make the degrees of every point to between the two boundaries. If you pick one edge, the degrees of two end points will both increase by one. Can you help X to check whether it is possible to fix the graph?

    Input
    There are at most 30 test cases.

    For each test case,The first line contains three integers N the number of left part graph vertices, M the number of right part graph vertices, and K the number of edges ( 1≤N≤2000,0≤M≤2000,0≤K≤6000). Vertices are numbered from 1 to N.

    The second line contains two numbers L,R(0≤L≤R≤300). The two fantastic numbers.

    Then K lines follows, each line containing two numbers U, V (1≤U≤N,1≤V≤M). It shows that there is a directed edge from U-th spot to V-th spot.

    Note. There may be multiple edges between two vertices.

    Output
    One line containing a sentence. Begin with the case number. If it is possible to pick some edges to make the graph fantastic, output "Yes" (without quote), else output "No" (without quote).

    样例输入
    3 3 7
    2 3
    1 2
    2 3
    1 3
    3 2
    3 3
    2 1
    2 1
    3 3 7
    3 4
    1 2
    2 3
    1 3
    3 2
    3 3
    2 1
    2 1

    样例输出
    Case 1: Yes
    Case 2: No

    题意

    一个二分图,左边N个点,右边M个点,中间K条边,问你是否可以删掉边使得所有点的度数在[L,R]之间

    题解

    比赛的时候写的网络流A的,赛后把自己hack了。。

    然后写了个贪心,发现还是贪心好写(雾)

    考虑两个集合A和B,A为L<=d[i]<=R,B为d[i]>R

    枚举每个边

    1.如果u和v都在B集合,直接删掉
    2.如果u和v都在A集合,无所谓
    3.如果u在B,v在A,并且v可删边即d[v]>L
    4.如果u在A,v在B,并且u可删边即d[u]>L

    最后枚举N+M个点判断是否在[L,R]之间

    这个做法虽然不是官方做法,如果有hack的数据可以发评论

    最后贴个官方做法,有源汇上下界网络流

    代码

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 
     4 const int maxn=6005;
     5 
     6 int main()
     7 {
     8     int N,M,K,L,R,o=1,u[maxn],v[maxn],d[maxn];
     9     while(scanf("%d%d%d",&N,&M,&K)!=EOF)
    10     {
    11         memset(d,0,sizeof d);
    12         scanf("%d%d",&L,&R);
    13         int sum=0,flag=1;
    14         for(int i=0;i<K;i++)
    15         {
    16             scanf("%d%d",&u[i],&v[i]);v[i]+=N;
    17             d[u[i]]++,d[v[i]]++;
    18         }
    19         for(int i=0;i<K;i++)
    20         {
    21             int uu=u[i],vv=v[i];
    22             if(d[uu]>R&&d[vv]>R)d[uu]--,d[vv]--;
    23             else if(L<=d[uu]&&d[uu]<=R&&L<=d[vv]&&d[vv]<=R)continue;
    24             else if(L+1<=d[uu]&&d[uu]<=R&&d[vv]>R)d[uu]--,d[vv]--;
    25             else if(d[uu]>R&&L+1<=d[vv]&&d[vv]<=R)d[uu]--,d[vv]--;
    26         }
    27         for(int i=1;i<=N+M;i++)if(d[i]<L||d[i]>R)flag=0;
    28         printf("Case %d: %s
    ",o++,flag?"Yes":"No");
    29     }
    30     return 0;
    31 }

    给一点测试数据,网上有的贪心过不去这些数据Yes Yes Yes Yes No

    4 4 16
    1 3
    1 1
    1 1
    2 2
    2 2
    3 3
    3 3
    4 4
    4 4
    1 1
    1 1
    2 2
    2 2
    3 3
    3 3
    4 4
    4 4
    
    4 3 6
    1 2
    1 1
    2 1
    2 2
    3 1
    3 1
    4 3
    
    4 4 10
    1 3
    1 2
    1 3
    2 1
    2 1
    2 1
    3 1
    3 2
    3 3
    4 3
    4 4
    
    3 3 7
    1 1
    1 2
    2 3
    1 3
    3 2
    3 3
    2 1
    2 1
    
    1 3 3
    1 1
    1 1
    1 2
    1 3

     官方做法

      1 #include<stdio.h>
      2 #include<string.h>
      3 #include<algorithm>
      4 using namespace std;
      5 
      6 const int maxn=1e5+5;
      7 const int maxm=2e5+5;
      8 const int INF=0x3f3f3f3f;
      9 
     10 int TO[maxm],CAP[maxm],NEXT[maxm],tote;
     11 int FIR[maxn],gap[maxn],cur[maxn],d[maxn],q[400000];
     12 int n,m,S,T;
     13 
     14 void add(int u,int v,int cap)
     15 {
     16     //printf("i=%d u=%d v=%d cap=%d
    ",tote,u,v,cap);
     17     TO[tote]=v;
     18     CAP[tote]=cap;
     19     NEXT[tote]=FIR[u];
     20     FIR[u]=tote++;
     21     
     22     TO[tote]=u;
     23     CAP[tote]=0;
     24     NEXT[tote]=FIR[v];
     25     FIR[v]=tote++;
     26 }
     27 void bfs()
     28 {
     29     memset(gap,0,sizeof gap);
     30     memset(d,0,sizeof d);
     31     ++gap[d[T]=1];
     32     for(int i=1;i<=n;++i)cur[i]=FIR[i];
     33     int head=1,tail=1;
     34     q[1]=T;
     35     while(head<=tail)
     36     {
     37         int u=q[head++];
     38         for(int v=FIR[u];v!=-1;v=NEXT[v])
     39             if(!d[TO[v]])
     40                 ++gap[d[TO[v]]=d[u]+1],q[++tail]=TO[v];
     41     }
     42 }
     43 int dfs(int u,int fl)
     44 {
     45     if(u==T)return fl;
     46     int flow=0;
     47     for(int &v=cur[u];v!=-1;v=NEXT[v])
     48         if(CAP[v]&&d[u]==d[TO[v]]+1)
     49         {
     50             int Min=dfs(TO[v],min(fl,CAP[v]));
     51             flow+=Min,fl-=Min,CAP[v]-=Min,CAP[v^1]+=Min;
     52             if(!fl)return flow;
     53         }
     54     if(!(--gap[d[u]]))d[S]=n+1;
     55     ++gap[++d[u]],cur[u]=FIR[u];
     56     return flow;
     57 }
     58 int ISAP()
     59 {
     60     bfs();
     61     int ret=0;
     62     while(d[S]<=n)ret+=dfs(S,INF);
     63     return ret;
     64 }
     65 
     66 int ca,N,M,Q,x,y,z,l[205][25],r[205][25];
     67 char op[2];
     68 
     69 void init()
     70 {
     71     tote=0;
     72     memset(FIR,-1,sizeof FIR);
     73 }
     74 int main()
     75 {
     76     int N,M,C,L,R,u,v,s,t,ca=1;
     77     while(scanf("%d%d%d",&N,&M,&C)!=EOF)
     78     {
     79         init();
     80         int in[6006]={0};
     81         s=N+M+1,t=s+1,S=t+1,T=S+1,n=T;
     82         add(t,s,INF);
     83         scanf("%d%d",&L,&R);
     84         for(int i=0;i<C;i++)
     85         {
     86             scanf("%d%d",&u,&v);
     87             add(u,N+v,1);
     88         }
     89         for(int i=1;i<=N;i++)
     90         {
     91             add(s,i,R-L);
     92             in[s]-=L;
     93             in[i]+=L;
     94         }
     95         for(int i=1;i<=M;i++)
     96         {
     97             add(i+N,t,R-L);
     98             in[i+N]-=L;
     99             in[t]+=L;
    100         }
    101         int sum=0;
    102         for(int i=1;i<=N+M+2;i++)
    103         {
    104             if(in[i]>0)
    105             {
    106                 add(S,i,in[i]);
    107                 sum+=in[i];
    108             }
    109             else
    110                 add(i,T,-in[i]);
    111         }
    112         printf("Case %d: %s
    ",ca++,sum==ISAP()?"Yes":"No");
    113     }
    114     return 0;
    115 }
  • 相关阅读:
    python的metaclass
    鱼和水的故事
    iOS的QuickTime Plugin
    二进制/十六进制转浮点数的编程(互转类似)
    Android开发常见错误及技巧
    Mac 热键大全
    Java动态程序设计:反射介绍
    注册asp.net 4.0 到iis
    javascript常用判断写法
    将存储过程执行的结果保存到临时表
  • 原文地址:https://www.cnblogs.com/taozi1115402474/p/9610719.html
Copyright © 2020-2023  润新知