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: Noc++

題意網絡

一個二分圖,左邊N個點,右邊M個點,中間K條邊,問你是否能夠刪掉邊使得全部點的度數在[L,R]之間測試

題解spa

比賽的時候寫的網絡流A的,賽後把本身hack了。。code

而後寫了個貪心,發現仍是貪心好寫(霧)blog

考慮兩個集合A和B,A爲L<=d[i]<=R,B爲d[i]>Rthree

枚舉每一個邊ip

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]>Lstring

最後枚舉N+M個點判斷是否在[L,R]之間it

這個作法雖然不是官方作法,若是有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\n",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\n",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\n",ca++,sum==ISAP()?"Yes":"No");
113     }
114     return 0;
115 }
相關文章
相關標籤/搜索