POJ 3155 Hard Life 最大密度子图

John is a Chief Executive Officer at a privately owned medium size company. The owner of the company has decided to make his son Scott a manager in the company. John fears that the owner will ultimately give CEO position to Scott if he does well on his new manager position, so he decided to make Scott’s life as hard as possible by carefully selecting the team he is going to manage in the company.

John knows which pairs of his people work poorly in the same team. John introduced a hardness factor of a team — it is a number of pairs of people from this team who work poorly in the same team divided by the total number of people in the team. The larger is the hardness factor, the harder is this team to manage. John wants to find a group of people in the company that are hardest to manage and make it Scott’s team. Please, help him.
这里写图片描述

In the example on the picture the hardest team consists of people 1, 2, 4, and 5. Among 4 of them 5 pairs work poorly in the same team, thus hardness factor is equal to 5⁄4. If we add person number 3 to the team then hardness factor decreases to 6⁄5.

Input
The first line of the input file contains two integer numbers n and m (1 ≤ n ≤ 100, 0 ≤ m ≤ 1000). Here n is a total number of people in the company (people are numbered from 1 to n), and m is the number of pairs of people who work poorly in the same team. Next m lines describe those pairs with two integer numbers ai and bi (1 ≤ ai, bi ≤ n, ai ≠ bi) on a line. The order of people in a pair is arbitrary and no pair is listed twice.

Output
Write to the output file an integer number k (1 ≤ k ≤ n) — the number of people in the hardest team, followed by k lines listing people from this team in ascending order. If there are multiple teams with the same hardness factor then write any one.

Sample Input
sample input #1
5 6
1 5
5 4
4 2
2 5
1 2
3 1

sample input #2
4 0
Sample Output
sample output #1
4
1
2
4
5

sample output #2
1
1
Hint
Note, that in the last example any team has hardness factor of zero, and any non-empty list of people is a valid answer.

题意:给你一个图,然你选出一个密度最大的子图。密度 = 边数/点数。

看了两天的论文和题解,终于想明白一点了。真的绕。。。头皮发麻。。就是胡伯涛的那篇算法合集之《最小割模型在信息学竞赛中的应用》 可以自己找一下,很容易找到。这种题目有两种做法。第一种:因为是选取一些边和他的点使密度最大,故g = E’/V’ 使g最大。构造函数 h(g) = max(E’ - g*v’) ,当h(g) = 0,此时显然g达到最大的结果。如果考虑把每条边都当作一个权值为1,的点。把原来的点当作权值为-g的边,此时就符合了最大权闭合图的做法。然后每次求出h(g),进行二分就可以了。然后残余网络中的点,就是要选择的点。

代码如下:

#include<iostream>
#include<cstring>
#include<cmath>
#include<vector>
#include<set>
#include<map>
#include<algorithm>
#include<cstdio>
#include<queue>
using namespace std;
const int MAX_V = 2300;
const double INF = 0x3f3f3f3f;
struct Edge{
    int to,rev;
    double cap;
    Edge();
    Edge(int _to,double _cap,int _rev);
};
vector<Edge> G[MAX_V];
int level[MAX_V],iter[MAX_V];
pair<int,int> p[MAX_V];
int N,M;
void add_Edge(int u,int v,double cap){
    G[u].push_back(Edge(v,cap,(int)G[v].size()));
    G[v].push_back(Edge(u,0,(int)G[u].size()-1));
}
void Creat_Map(double g){
    for(int i=0;i<=N+M+1;++i) G[i].clear();
    int s = 0,t = N+M+1;
    for(int i=1;i<=N;++i){
        add_Edge(i,t,g);
    }
    for(int i=1;i<=M;++i){
        add_Edge(N+i,p[i].first,INF);
        add_Edge(N+i,p[i].second,INF);
        add_Edge(s,N+i,1.0);
    }
}

void bfs(int s){
    memset(level,-1,sizeof(level));
    queue<int> q;
    level[s] = 0;q.push(s);
    while(!q.empty()){
        int v = q.front();q.pop();
        for(int i=0;i<G[v].size();i++){
            Edge &e = G[v][i];
            if(e.cap > 0 && level[e.to] < 0){
                level[e.to] = level[v] + 1;
                q.push(e.to);
            }
        }
    }
}

double dfs(int s,int t,double f){
    if(s == t)  return f;
    for(int &i = iter[s];i < G[s].size();i++){
        Edge &e = G[s][i];
        if(e.cap > 0 && level[e.to] > level[s]){
            double d = dfs(e.to,t,min(f,e.cap));
            if(d > 0){
                e.cap -= d;
                G[e.to][e.rev].cap += d;
                return d;
            }
        }
    }
    return 0;
}
double max_flow(int s,int t){
    double flow = 0;
    while(true){
        bfs(s);
        if(level[t] < 0)    return flow;
        memset(iter,0,sizeof(iter));
        double f;
        while((f = dfs(s,t,INF)) > 0)
            flow += f;
    }
}
bool used[MAX_V];
void dfs(int s){
   // cout << s << endl;
    used[s] = true;
    for(int i=0;i<G[s].size();++i){
         Edge &e = G[s][i];
      //   cout << e.to << " " << e.cap << endl;
         if(!used[e.to] && e.cap > 0){
     //       printf("to = %d,cap = %lf\n",e.to,e.cap);
            dfs(e.to);
         }
    }
}
//#define Local
int main(void){
    #ifdef Local
        freopen("in.txt","r",stdin);
    #endif // Local
    scanf("%d%d",&N,&M);
    if(M == 0){
        cout << 1 << endl;
        cout << 1 << endl;
        return 0;
    }
    int u,v;
    for(int i=1;i<=M;++i){
        scanf("%d%d",&p[i].first,&p[i].second);
    }
    int s = 0,t = N+M+1;
    double l = 0,r = M;
    double Min = 1.0/N/N;
    while(r - l >= Min){
        double mid = (l+r)/2;
        Creat_Map(mid);
        double f = M - max_flow(s,t);
        if(f > 0)
            l = mid;
        else
            r = mid;
    //  cout << f << endl;
    }
    Creat_Map(l);
    memset(used,false,sizeof(used));
    max_flow(s,t);
    dfs(s);
    vector<int> vec;
    for(int i=1;i<=N;++i){
        if(used[i]){
           vec.push_back(i);
        }
    }
    cout << vec.size() << endl;
    for(int i=0;i<vec.size();++i){
        cout << vec[i] << endl;
    }
    return 0;
}
Edge::Edge(){
    to = rev = 0;
    cap = 0;
}
Edge::Edge(int _to,double _cap,int _rev){
    to = _to;
    cap = _cap;
    rev = _rev;
}

不过这种做法,因为把边都当作点了,对图进行的增加,使得复杂度也剧增,所以有了第二种做法,这种复杂度比较好。

但是本人惭愧,看得稀里糊涂,描述不出来。大家直接看那篇论文吧。做法就是
h(g) = (N*M - max_flow)/2;
建图是s到每个点权值为M,每个点到t权值为M+2*g-Deg[i]
点与点之间的边建立权值为1.0;
二分时考虑h(g)的结果,使其二分到0,故当h(g) > 0,则l = mid;
最后再用l建图,再跑一下次,残余网络中能到达的点,则为要选择的点。

代码如下:

#include<iostream>
#include<cstring>
#include<cmath>
#include<vector>
#include<set>
#include<map>
#include<algorithm>
#include<cstdio>
#include<queue>
using namespace std;
const double eps = 1e-8;
const int MAX_V = 2300;
const double INF = 0x3f3f3f3f;
struct Edge{
    int to,rev;
    double cap;
    Edge();
    Edge(int _to,double _cap,int _rev);
};
vector<Edge> G[MAX_V];
int level[MAX_V],iter[MAX_V],Deg[MAX_V];
pair<int,int> p[MAX_V];
int N,M;
void add_Edge(int u,int v,double cap){
    G[u].push_back(Edge(v,cap,(int)G[v].size()));
    G[v].push_back(Edge(u,0,(int)G[u].size()-1));
}
void Creat_Map(double g){
    for(int i=0;i<=N+M+1;++i) G[i].clear();
    int s = 0,t = N+M+1;
    for(int i=1;i<=N;++i){
        add_Edge(s,i,(double)M);
        add_Edge(i,t,(double)(M+2*g-Deg[i]));
    }
    for(int i=1;i<=M;++i){
        add_Edge(p[i].first,p[i].second,1.0);
        add_Edge(p[i].second,p[i].first,1.0);
    }
}

void bfs(int s){
    memset(level,-1,sizeof(level));
    queue<int> q;
    level[s] = 0;q.push(s);
    while(!q.empty()){
        int v = q.front();q.pop();
        for(int i=0;i<G[v].size();i++){
            Edge &e = G[v][i];
            if(e.cap > eps && level[e.to] < 0){
                level[e.to] = level[v] + 1;
                q.push(e.to);
            }
        }
    }
}

double dfs(int s,int t,double f){
    if(s == t)  return f;
    for(int &i = iter[s];i < G[s].size();i++){
        Edge &e = G[s][i];
        if(e.cap > 0 && level[e.to] > level[s]){
            double d = dfs(e.to,t,min(f,e.cap));
            if(d > 0){
                e.cap -= d;
                G[e.to][e.rev].cap += d;
                return d;
            }
        }
    }
    return 0;
}
double max_flow(int s,int t){
    double flow = 0;
    while(true){
        bfs(s);
        if(level[t] < 0)    return flow;
        memset(iter,0,sizeof(iter));
        double f;
        while((f = dfs(s,t,INF)) > 0)
            flow += f;
    }
}
bool used[MAX_V];
void dfs(int s){
    used[s] = true;
    for(int i=0;i<G[s].size();++i){
         Edge &e = G[s][i];
         if(!used[e.to] && e.cap > 0){
            dfs(e.to);
         }
    }
}
//#define Local
int main(void){
    #ifdef Local
        freopen("in.txt","r",stdin);
    #endif // Local
    scanf("%d%d",&N,&M);
    if(M == 0){
        cout << 1 << endl;
        cout << 1 << endl;
        return 0;
    }
    int u,v;
    for(int i=1;i<=M;++i){
        scanf("%d%d",&p[i].first,&p[i].second);
        Deg[p[i].first]++;
        Deg[p[i].second]++;
    }
    int s = 0,t = N+M+1;
    double l = 0,r = M;
    double Min = 1.0/N/N;
    while(r - l >= Min){
        double mid = (l+r)/2;
        Creat_Map(mid);
        double f = (N*M*1.0 - max_flow(s,t))/2.0;
        if(f > 0)
            l = mid;
        else
            r = mid;
    }
    Creat_Map(l);
    memset(used,false,sizeof(used));
    max_flow(s,t);
    dfs(s);
    vector<int> vec;
    for(int i=1;i<=N;++i){
        if(used[i]){
           vec.push_back(i);
        }
    }
    cout << vec.size() << endl;
    for(int i=0;i<vec.size();++i){
        cout << vec[i] << endl;
    }
    return 0;
}
Edge::Edge(){
    to = rev = 0;
    cap = 0;
}
Edge::Edge(int _to,double _cap,int _rev){
    to = _to;
    cap = _cap;
    rev = _rev;
}

猜你喜欢

转载自blog.csdn.net/zhao5502169/article/details/81811537
今日推荐