[uva1389]Hard Life
最大密度子图
二分枚举答案$k$,问题即求$\max_{V}\left(\sum_{x,y\in V}[(x,y)\in E]-k|V|\right)$
记$d_{x}$为$x$的度数,则上式也即$-\frac{1}{2}\min_{V}\left(\sum_{x\in V,y\not\in V}[(x,y)\in E]+\sum_{x\in V}(2k-d_{x})\right)$
注意到$\sum_{x\in V,y\not\in V}[(x,y)\in E]$与最小割类似,并将$2k-d_{x}$按正负分别连向$S$和$T$
此时,以$\sum_{2k<d_{x}}(2k-d_{x})$为基础,将最终不与$S$连通的作为$V$,割的代价恰为上式
另外,上述过程需以实数为流量,实际上可以避免
考虑两张不同密度的子图,两者密度差即$\frac{m_{1}}{n_{1}}-\frac{m_{2}}{n_{2}}=\frac{m_{1}n_{2}-m_{2}n_{1}}{n_{1}n_{2}}\ge \frac{1}{n^{2}}$
记最大密度$\rho\in (\frac{D}{n^{2}},\frac{D+1}{n^{2}}]$(其中$D\in N$),则该范围内可行密度仅有$\rho$
换言之,对$k=\frac{D}{n^{2}}$求出原式$>0$的方案后,对应的子图即为最大密度子图
二分$D$即可,时间复杂度为$o(\log m\times \max Flow(n,m))$,可以通过
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N=105,M=1005; 5 int n,m,cnt,d[N],vis[N],x[M],y[M]; 6 namespace Dinic{ 7 const int N=105,M=1105; 8 int S,T,E,head[N],Head[N],d[N]; 9 ll ans;queue<int>q; 10 struct edge{ 11 int nex,to;ll len; 12 }e[M<<1]; 13 void init(){ 14 E=0; 15 memset(head,-1,sizeof(head)); 16 } 17 void add(int x,int y,ll z){ 18 e[E]=edge{head[x],y,z},head[x]=E++; 19 e[E]=edge{head[y],x,0},head[y]=E++; 20 } 21 bool bfs(){ 22 memset(d,-1,sizeof(d)); 23 d[S]=0,q.push(S); 24 while (!q.empty()){ 25 int k=q.front();q.pop(); 26 for(int i=head[k];i!=-1;i=e[i].nex){ 27 int u=e[i].to; 28 if ((e[i].len)&&(d[u]<0))d[u]=d[k]+1,q.push(u); 29 } 30 } 31 return d[T]>=0; 32 } 33 ll dfs(int k,ll s){ 34 if (k==T)return s; 35 ll ans=0; 36 for(int &i=head[k];i!=-1;i=e[i].nex){ 37 int u=e[i].to; 38 if ((e[i].len)&&(d[u]==d[k]+1)){ 39 ll p=dfs(u,min(s,(ll)e[i].len)); 40 e[i].len-=p,e[i^1].len+=p,s-=p,ans+=p; 41 if (!s)return ans; 42 } 43 } 44 return ans; 45 } 46 ll query(int s,int t){ 47 S=s,T=t,ans=0; 48 memcpy(Head,head,sizeof(head)); 49 while (bfs()){ 50 ans+=dfs(S,1e18); 51 memcpy(head,Head,sizeof(head)); 52 } 53 return ans; 54 } 55 void dfs(int k){ 56 if (vis[k])return; 57 vis[k]=1,cnt-=(k>0); 58 for(int i=head[k];i!=-1;i=e[i].nex) 59 if (e[i].len)dfs(e[i].to); 60 } 61 }; 62 bool check(int k){ 63 Dinic::init(); 64 k<<=1; 65 for(int i=1;i<=n;i++){ 66 if (d[i]<k)Dinic::add(0,i,k-d[i]); 67 else Dinic::add(i,n+1,d[i]-k); 68 } 69 for(int i=1;i<=m;i++){ 70 Dinic::add(x[i],y[i],n*n); 71 Dinic::e[Dinic::E-1].len=n*n; 72 } 73 ll ans=Dinic::query(0,n+1); 74 for(int i=1;i<=n;i++) 75 if (d[i]>k)ans+=k-d[i]; 76 return ans<0; 77 } 78 int main(){ 79 while (scanf("%d%d",&n,&m)!=EOF){ 80 for(int i=0;i<=n;i++)d[i]=vis[i]=0; 81 for(int i=1;i<=m;i++){ 82 scanf("%d%d",&x[i],&y[i]); 83 d[x[i]]++,d[y[i]]++; 84 } 85 for(int i=1;i<=n;i++)d[i]*=n*n; 86 if (!m){ 87 printf("1\n1\n"); 88 continue; 89 } 90 int l=0,r=n*n*m; 91 while (l<r){ 92 int mid=(l+r+1>>1); 93 if (check(mid))l=mid; 94 else r=mid-1; 95 } 96 check(l); 97 cnt=n,Dinic::dfs(0); 98 printf("%d\n",cnt); 99 for(int i=1;i<=n;i++) 100 if (!vis[i])printf("%d\n",i); 101 } 102 return 0; 103 }