[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 }
View Code

 

posted @ 2022-09-28 18:54  PYWBKTDA  阅读(53)  评论(0编辑  收藏  举报