HDU 5639 Deletion 二分+网络流
题意:bc round 74 div1
分析:
考虑删掉的边的形态, 就是我们经常见到的环套树这种结构, 参考平时这种图给出的方法, 如果一个图的每个点的出边只有一条,
那么一定会构成环套树这种结构. 于是问题可以转化成, 给无向图的每条边定向, 使得出度最大点的出度最小 (每个点的出度大小对应了删的次数).
题解给出三种做法,对每条边定向,我采取第二种
(官方题解)类似方法一, 要求的无非是每条边的归属问题, 对于每条边(a,b), 它可以属于a或者b,
那么新建一个节点表示这条边并和a,b都相邻, 这样就得到了一个二分图. 左边是原图中的节点, 右边是原图中的边.
二分每个左边每个节点的容量k, 如果右边的点能够完全匹配, 那么这个k就是可行的, 找到最小的k即可. 转化成二分图多重匹配问题.
这个地方就是二分图,一部分是点,一部分是边,一条边和其左右两个点相连,这样二分每个节点的容量k,
即源点和每个顶点建边,流量为k,然后按照题解建点和边的边,流量为1,然后每个表示边的点建一条边流向汇点,流量为1,
,当流过一条边时,就相当于给它定向,然后二分图求最大流,就可以了,判定,流量是不是等于m就行
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <iostream> #include <cstdio> #include <vector> #include <cstring> #include <queue> #include <cmath> using namespace std; typedef long long LL; const int mod=1e9+7; const int INF=0x3f3f3f3f; const int maxn=4e3+5; struct Edge { int from,to,cap,flow; Edge(int u,int v,int c,int d):from(u),to(v),cap(c),flow(d) {} }; int x[maxn],y[maxn],n,m; struct dinic { int s,t; vector<Edge>edges; vector<int>G[maxn]; int d[maxn]; int cur[maxn]; bool vis[maxn]; void init() { edges.clear(); for(int i=0;i<maxn;++i) G[i].clear(); } bool bfs() { memset(vis,0,sizeof(vis)); queue<int>q; q.push(s); d[s]=0; vis[s]=1; while(!q.empty()) { int x=q.front(); q.pop(); for(int i=0; i<G[x].size(); i++) { Edge &e= edges[G[x][i]]; if(!vis[e.to]&&e.cap>e.flow) { vis[e.to]=1; d[e.to]=d[x]+1; q.push(e.to); } } } return vis[t]; } int dfs(int x,int a) { if(x==t||a==0)return a; int flow=0,f; for(int &i=cur[x]; i<G[x].size(); i++) { Edge &e=edges[G[x][i]]; if(d[x]+1==d[e.to]&&(f=dfs(e.to,min(a,e.cap-e.flow)))) { e.flow+=f; edges[G[x][i]^1].flow-=f; flow+=f; a-=f; if(a==0)break; } } return flow; } int maxflow(int s,int t) { this->s=s; this->t=t; int flow=0; while(bfs()) { memset(cur,0,sizeof(cur)); flow+=dfs(s,INF); } return flow; } void addedge(int u,int v,int c) { Edge x(u,v,c,0),y(v,u,0,0); edges.push_back(x); edges.push_back(y); int l=edges.size(); G[u].push_back(l-2); G[v].push_back(l-1); } }solve; bool fun(int s) { solve.init(); for(int i=1;i<=n;++i) solve.addedge(0,i,s); for(int i=1;i<=m;++i) { solve.addedge(x[i],i+n,1); solve.addedge(y[i],i+n,1); } for(int i=n+1;i<=n+m;++i) solve.addedge(i,n+m+1,1); int ans=solve.maxflow(0,n+m+1); if(ans==m)return 1; return 0; } int getans() { if(m==0)return 0; int l=0,r=m; while(l<r) { int mid=(l+r)>>1; if(fun(mid))r=mid; else l=mid+1; } return (l+r)>>1; } int main() { int T; scanf("%d", &T); while(T--) { scanf("%d%d",&n,&m); for(int i=1;i<=m;++i) scanf("%d%d",&x[i],&y[i]); printf("%d\n",getans()); } return 0; }