http://poj.org/problem?id=3155
最大密度子图和最大权闭合图性质很相近(大概可以这么说吧),一个是取最多的边一个是取最多有正贡献的点,而且都是有选一种必须选另一种的限制,一个是选边必须选其两边的点,一个是选正权点必须选其相邻的负权点。
那么就可以把最大密度子图用最大权闭合图相近的方式写,二分+网络流就可以了,网络流建图方法可以参考我上一篇博客。
https://blog.csdn.net/power721/article/details/6781518 也就是该博客的第一种做法,不写第二种因为我懒,over。
顺便我的写法设置的精度单位(随便叫了个名字,领会精神)是1.0/n/n,有自环的话有点不靠谱,1e-4什么的可能逻辑上更合理一点。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<cmath> 5 #include<iostream> 6 #include<queue> 7 using namespace std; 8 #define LL long long 9 const int maxn=2010; 10 const double minf=1e14; 11 const double eps=1.0/1e16; 12 int n,m,s,t; 13 LL val[maxn]={}; 14 int a[maxn][2]={}; 15 struct nod{ 16 int y,next;double v; 17 }e[maxn*10]; int head[maxn],tot=1; 18 queue<int>q; int dep[maxn]={}; 19 int zz[maxn]={},tly=0,vis[maxn]={}; 20 inline void init(int x,int y,double v){ 21 e[++tot].y=y;e[tot].v=v;e[tot].next=head[x];head[x]=tot; 22 } 23 bool dfs(){ 24 memset(dep,0,sizeof(dep)); 25 q.push(s);dep[s]=1; 26 while(!q.empty()){ 27 int x=q.front();q.pop(); 28 for(int i=head[x];i;i=e[i].next){ 29 if(e[i].v>eps&&!dep[e[i].y]){ 30 dep[e[i].y]=dep[x]+1; 31 q.push(e[i].y); 32 } 33 } 34 } 35 return dep[t]; 36 } 37 double dfs1(int x,double fc){ 38 if(x==t){ 39 return fc; 40 } 41 double he=0,z; 42 for(int i=head[x];i;i=e[i].next){ 43 if(dep[x]+1==dep[e[i].y]){ 44 z=dfs1(e[i].y,min(fc-he,e[i].v)); 45 he+=z;e[i].v-=z;e[i^1].v+=z; 46 if(fc-he<eps)break; 47 } 48 } 49 return he; 50 } 51 bool check(double v){ 52 memset(head,0,sizeof(head));tot=1; 53 for(int i=1;i<=m;i++){ 54 init(n+i,a[i][1],minf);init(a[i][1],n+i,0); 55 init(n+i,a[i][0],minf);init(a[i][0],n+i,0); 56 init(s,n+i,1.0);init(n+i,s,0); 57 } 58 for(int i=1;i<=n;i++){init(i,t,v);init(t,i,0);} 59 while(dfs())dfs1(s,minf); 60 for(int i=1;i<=m;i++){ 61 int z=(i-1)*6+1+5; 62 if(e[z].v>eps){ 63 return 1; 64 } 65 } 66 return 0; 67 } 68 void dfs2(int x){ 69 if(x==t)return; 70 if(x<=n)zz[++tly]=x; 71 vis[x]=1; 72 for(int i=head[x];i;i=e[i].next){ 73 if(vis[e[i].y]||e[i].v<eps)continue; 74 dfs2(e[i].y); 75 } 76 } 77 int main(){ 78 scanf("%d%d",&n,&m);s=n+m+1;t=s+1; 79 if(n==0){ printf("0 ");return 0; } 80 if(m==0){ printf("1 1 ");return 0; } 81 for(int i=1;i<=m;i++){scanf("%d%d",&a[i][0],&a[i][1]);} 82 double l=0.5,r=m,mid;r=max(r,1.0); 83 double mi=1.0/(double)n/(double)n; 84 while(r-l>mi){ 85 mid=(l+r)/2; 86 if(check(mid))l=mid; 87 else r=mid; 88 } 89 check(l-mi); 90 dfs2(s); 91 printf("%d ",tly);sort(zz+1,zz+1+tly); 92 for(int i=1;i<=tly;i++)printf("%d ",zz[i]); 93 return 0; 94 }