HOME Back
查了题解才知道网络流。。。
可是苟蒻根本想不到
二分答案,每个节点到它参加的比赛连一条容量为1的边
比赛到超级汇连一条容量为1的边
超级源到每个点连一条容量为当前答案的边
dicnic检查当前最大流是否等于m即可
#include<iostream> #include<cstdio> #include<algorithm> #include<queue> #include<vector> #include<cstring> using namespace std; const int maxn = 2E4 + 10; const int INF = ~0U>>1; struct E{ int from,to,cap,flow; }edgs[maxn*10]; int n,m,cnt,dis[maxn],cur[maxn]; vector <int> v[maxn]; queue <int> q; void Add(int x,int y,int cap) { edgs[2*cnt] = (E){x,y,cap,0}; v[x].push_back(2*cnt); edgs[2*cnt^1] = (E){y,x,0,0}; v[y].push_back(2*cnt^1); ++cnt; } void CLEAR(int now) { for (int i = 0; i <= 2*cnt + 1; i++) edgs[i].flow = 0; for (int i = 0; i < n; i++) edgs[i*2].cap = now; } bool BFS() { memset(dis,0,sizeof(dis)); dis[0] = 1; q.push(0); while (!q.empty()) { int k = q.front(); q.pop(); for (int i = 0; i < v[k].size(); i++) { int to = edgs[v[k][i]].to; if (dis[to] || edgs[v[k][i]].flow == edgs[v[k][i]].cap) continue; dis[to] = dis[k] + 1; q.push(to); } } return dis[n+m+1]; } int Dicnic(int x,int a) { if (x == n + m + 1 || !a) return a; int flow = 0,f; for (int &i = cur[x]; i < v[x].size(); i++) { E &e = edgs[v[x][i]]; if (e.flow == e.cap || (dis[x] + 1) != dis[e.to]) continue; f = Dicnic(e.to,min(a,e.cap - e.flow)); if (f) { flow += f; a -= f; e.flow += f; edgs[v[x][i]^1].flow -= f; if (!a) break; } } return flow; } bool Judge(int now) { CLEAR(now); int flow = 0; while (BFS()) { memset(cur,0,sizeof(cur)); flow += Dicnic(0,INF); } return flow == m; } int main() { #ifdef YZY freopen("yzy.txt","r",stdin); #endif cin >> n >> m; for (int i = 1; i <= n; i++) Add(0,i,0); for (int i = 1; i <= m; i++) { int x,y; scanf("%d%d",&x,&y); Add(x,i + n,1); Add(y,i + n,1); Add(i + n,n + m + 1,1); } int L,R; L = 0; R = 10000; while (R - L > 1) { int mid = (L+R) >> 1; if (Judge(mid)) R = mid; else L = mid; } if (Judge(L)) cout << L; else cout << R; return 0; }