Bzoj1312 / POJ3155 Neerc2006 Hard Life

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 459  Solved: 114

Description

在一家公司中,人事部经理与业务部经理不和。一次,总经理要求人事部从公司的职员中挑选出一些来帮助业务部经理完成一项任务。人事部经理发现,在公司的所有职员中,有一些人相处得很不好。如果把他们同时放在一个工作小组中,他们将会给主管带来不小的麻烦。人事部经理还知道,在一个工作小组中,主管人员的麻烦程度可以认为是(带来麻烦的人的对数/总人数) 。于是,人事部经理决定选取这样的一些人,使得业务部经理的麻烦度最大。你的任务是帮助人事部经理达到他的目的。 在这样的一个公司中,保证公司的人数小于100 人,带来麻烦的员工不会多于1000 对。

Input

第一行给出N,M代表共有N个人,M对人之间有怨念 下面M行,每行两个数,代表这两个人有怨念

Output

输出最多能找出多少个人,人数>=1

Sample Input

5 6
1 5
5 4
4 2
2 5
1 2
3 1

Sample Output

4

HINT

Source

图论 最大密度子图 01分数规划 网络流

将人抽象成点,关系抽象成边,则“带来麻烦的人的对数/总人数”就是一个子图中边数/点数,这玩意儿叫做图的密度。

原题POJ3155 要求输出密度最大时的任一方案

这里要求输出密度最大时最多能选出多少个人。

设密度r=边数/点数,显然是一个01分数规划问题。

解法1:

  将每条边看做一个点,对于原图中的一条无向边<u,v>,从代表<u,v>的点向点u和点v各连一条边,容量为INF;

  从S向<u,v>连边,容量为1

  从u和v向T连边,容量为r

  ↑原问题转化成了最大权闭合子图问题。

解法2:

  证明见胡伯涛《最小割模型在信息学竞赛中的应用》

  U=m

  从S向u连边,容量为U

  从v向T连边,容量为U+2*r-deg[v]

  对于边<u,v>从u向v连边,容量为1

  若$(m*n-maxflow)/2>0$说明r可以扩大

这样就求出了最大的r

再用这个r建一遍图,跑最大流,在残量网络上DFS就可以找出所有可选的点。

就可以过POJ3155

把输出方案去掉就可以过Bzoj1312

但是博主傻傻不能理解为什么这样贪心一定能选出最多的人

  1 /*by SilverN*/
  2 #include<iostream>
  3 #include<algorithm>
  4 #include<cstdio>
  5 #include<cmath>
  6 #include<cstring>
  7 #include<queue>
  8 #define LL long long
  9 using namespace std;
 10 const int INF=0x3f3f3f3f;
 11 const double eps=1e-5;
 12 const int mxn=1005;
 13 int read(){
 14     int x=0,f=1;char ch=getchar();
 15     while(ch<‘0‘ || ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
 16     while(ch>=‘0‘ && ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
 17     return x*f;
 18 }
 19 struct EG{
 20     int x,y;
 21 }eg[mxn<<4];
 22 int deg[mxn];
 23 //
 24 struct edge{
 25     int v,nxt;
 26     double f;
 27 }e[mxn<<4];
 28 int hd[mxn],mct=1;
 29 inline void add_edge(int u,int v,double f){
 30     e[++mct].v=v;e[mct].nxt=hd[u];e[mct].f=f;hd[u]=mct;return;
 31 }
 32 void insert(int u,int v,double f){
 33     add_edge(u,v,f); add_edge(v,u,0);
 34     return;
 35 }
 36 //
 37 int n,m,S,T,U;
 38 int d[mxn];
 39 bool BFS(){
 40     memset(d,0,sizeof d);
 41     queue<int>q;
 42     d[S]=1;
 43     q.push(S);
 44     while(!q.empty()){
 45         int u=q.front();q.pop();
 46         for(int i=hd[u];i;i=e[i].nxt){
 47             int v=e[i].v;
 48             if(!d[v] && e[i].f>0){
 49                 d[v]=d[u]+1;
 50                 q.push(v);
 51             }
 52         }
 53     }
 54     return d[T];
 55 }
 56 double DFS(int u,double lim){
 57     if(u==T)return lim;
 58     double f=0,tmp;
 59     for(int i=hd[u];i;i=e[i].nxt){
 60         int v=e[i].v;
 61         if(d[v]==d[u]+1 && e[i].f>eps && (tmp=DFS(v,min(lim,e[i].f)))){
 62             e[i].f-=tmp;
 63             e[i^1].f+=tmp;
 64             lim-=tmp;
 65             f+=tmp;
 66             if(fabs(lim)<eps)return f;
 67         }
 68     }
 69     d[u]=0;
 70     return f;
 71 }
 72 double Dinic(){
 73     double res=0;
 74     while(BFS())res+=DFS(S,INF);
 75     return res;
 76 }
 77 void Build(double r){
 78     memset(hd,0,sizeof hd);mct=1;
 79     S=0;T=n+1;int i;
 80     for(i=1;i<=n;i++){
 81         insert(S,i,U);
 82         insert(i,T,U+2*r-deg[i]);
 83     }
 84     for(i=1;i<=m;i++){
 85         add_edge(eg[i].x,eg[i].y,1);
 86         add_edge(eg[i].y,eg[i].x,1);
 87     }
 88     return;
 89 }
 90 bool use[mxn];int cnt=0;
 91 void DFS(int u){
 92     use[u]=1;++cnt;
 93     for(int i=hd[u];i;i=e[i].nxt){
 94         if(!use[e[i].v] && e[i].f>eps){DFS(e[i].v);}
 95     }
 96     return;
 97 }
 98 void solve(){
 99     double l=0,r=m; U=m;
100     double X=1.0/n/n;
101     while(r-l>X){
102         double mid=(l+r)/2;
103         Build(mid);
104 //        printf("mid:%.3f\n",mid);
105         if((m*n-Dinic())/2>=eps){
106             l=mid;
107         }else r=mid;
108     }
109     Build(l);Dinic();
110     return;
111 }
112 void init(){
113     memset(hd,0,sizeof hd);mct=1;
114     memset(use,0,sizeof use);cnt=0;
115     return;
116 }
117 int main(){
118     while(scanf("%d%d",&n,&m)!=EOF){
119         if(!m){printf("1\n1\n");continue;}
120         init();
121         for(int i=1;i<=m;i++){
122             eg[i].x=read();eg[i].y=read();
123             ++deg[eg[i].x];
124             ++deg[eg[i].y];
125         }
126         solve();
127         DFS(S);
128         printf("%d\n",cnt-1);
129         for(int i=1;i<=n;i++)if(use[i])printf("%d\n",i);
130         break;
131     }
132     return 0;
133 }
时间: 2024-11-05 19:44:23

Bzoj1312 / POJ3155 Neerc2006 Hard Life的相关文章

POJ3155 Hard Life

Time Limit: 8000MS   Memory Limit: 65536K Total Submissions: 8482   Accepted: 2461 Case Time Limit: 2000MS   Special Judge Description John is a Chief Executive Officer at a privately owned medium size company. The owner of the company has decided to

POJ3155 Hard Life [最大密度子图]

Hard Life Time Limit: 8000MS   Memory Limit: 65536K Total Submissions: 8646   Accepted: 2514 Case Time Limit: 2000MS   Special Judge Description John is a Chief Executive Officer at a privately owned medium size company. The owner of the company has

poj3387[NEERC2006]IdealFrame

其实只是把别人的题解强行扩写了 写这篇题解之前我不会的预备知识: 欧拉通路:从图中一个点出发不重复地遍历所有边的路径(可以停在另一个点) 欧拉回路:从图中一个点出发不重复地遍历所有边的回路(必须回到出发点) 欧拉图:存在欧拉回路的图.判断无向图为欧拉图的充要条件是所有点的度数均为偶数. 半欧拉图:存在欧拉通路的图.判断无向图为欧拉图的充要条件是所有点的度数均为偶数或只有两个点的度数为奇数. 一个图中如果存在度数为奇数的点,那么这样的点一定有偶数个. 从一些简单的例子考虑到复杂的例子. 给定的图是

poj3155 最大密度子团

求最大密度子团 记得在最后一次寻找的时候记得将进入的边放大那么一点点,这样有利于当每条边都满流的情况下会选择点 #include <iostream> #include <algorithm> #include <string.h> #include <cstdio> #include <vector> #include <queue> #include <cmath> using namespace std; const

bzoj1312

忘写题解了,经典的最大密度子图 可以类似分数规划的做,二分密度,然后转化为最大权闭合子图做,判断是否大于0 注意方案的输出 1 const eps=1e-6; 2 lim=1e-12; 3 inf=1000000007; 4 type node=record 5 po,next:longint; 6 flow:double; 7 end; 8 9 var e:array[0..800010] of node; 10 numh,h,cur,pre,p,x,y:array[0..2010] of l

【POJ3155】Hard Life 分数规划+最小割

链接: #include <stdio.h> int main() { puts("转载请注明出处[辗转山河弋流歌 by 空灰冰魂]谢谢"); puts("网址:blog.csdn.net/vmurder/article/details/46437961"); } 题解: 如题.先算出那个分数值,然后看有哪些人还与源点相连. 最小割建图:原图每个点对应一个点,原图每条边对应一个点.每条边对应点向两端点对应点连边,注意要单向边. 这道题卡精度: 所以一些细

acm常见算法及例题

转自:http://blog.csdn.net/hengjie2009/article/details/7540135 acm常见算法及例题 初期:一.基本算法:     (1)枚举. (poj1753,poj2965)     (2)贪心(poj1328,poj2109,poj2586)     (3)递归和分治法.     (4)递推.     (5)构造法.(poj3295)     (6)模拟法.(poj1068,poj2632,poj1573,poj2993,poj2996)二.图算法

ACM算法总结及刷题参考

参考:http://bbs.byr.cn/#!article/ACM_ICPC/11777 OJ上的一些水题(可用来练手和增加自信)(poj3299,poj2159,poj2739,poj1083,poj2262,poj1503,poj3006,poj2255,poj3094) 初期: 一.基本算法: (1)枚举. (poj1753,poj2965)    (2)贪心(poj1328,poj2109,poj2586)    (3)递归和分治法.     (4)递推.     (5)构造法.(po

POJ题目推荐(转载)

POJ推荐50题1.标记“难”和“稍难”的题目可以看看,思考一下,不做要求,当然有能力的同学可以直接切掉.2.标记为A and B的题目是比较相似的题目,建议大家两个一起做,可以对比总结,且二者算作一个题目.3.列表中大约有70个题目.大家选做其中的50道,且每类题目有最低数量限制.4.这里不少题目在BUPT ACM FTP上面都有代码,请大家合理利用资源.5.50个题目要求每个题目都要写总结,养成良好的习惯.6.这个列表的目的在于让大家对各个方面的算法有个了解,也许要求有些苛刻,教条,请大家谅