pku 3155 Hard Life 最大密集子图

http://poj.org/problem?id=3155

题意:

给定一个无向图,求该图的一个子图使得该子图中边/点的权值最大;

思路:

证明看论文:http://wenku.baidu.com/view/986baf00b52acfc789ebc9a9.html

建图方法:

把原图中的无向边转换成两条有向边,容量为1;

设一源点,连接所有点,容量为U

设一汇点,所有点连接汇点,容量为 U+2g-du

二分枚举最大密度g,其中du为u的度。

U一般取边数即可。

//#pragma comment(linker,"/STACK:327680000,327680000")
#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#include <string>
#include <set>
#include <functional>
#include <numeric>
#include <sstream>
#include <stack>
#include <map>
#include <queue>

#define CL(arr, val)    memset(arr, val, sizeof(arr))

#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define ll long long
#define L(x)    (x) << 1
#define R(x)    (x) << 1 | 1
#define MID(l, r)   (l + r) >> 1
#define Min(x, y)   (x) < (y) ? (x) : (y)
#define Max(x, y)   (x) < (y) ? (y) : (x)
#define E(x)        (1 << (x))
#define iabs(x)     (x) < 0 ? -(x) : (x)
#define OUT(x)  printf("%I64d\n", x)
#define lowbit(x)   (x)&(-x)
#define Read()  freopen("din.txt", "r", stdin)
#define Write() freopen("dout.txt", "w", stdout);


#define M 1000007
#define N 1107

using namespace std;

const double inf = ~0u;
const double eps = 1e-6;
double lim;

struct node
{
    int v;
    double w;
    int next;
}g[M];
int head[N],ct;
int q[N*100];

int level[N];
bool vt[N];

struct t_node
{
    int u,v;
}t_g[N];

int path[N],len;
int du[N];
int n,m;

void add(int u,int v,double w)
{
    g[ct].v = v;
    g[ct].w = w;
    g[ct].next = head[u];
    head[u] = ct++;

    g[ct].v = u;
    g[ct].w = 0;
    g[ct].next = head[v];
    head[v] = ct++;
}
bool layer(int s,int e){
    int i;
    CL(level,-1);
    level[s] = 0;
    int l,r;
    l = r = 0;
    q[r] = s;
    while (l <= r){
        int u = q[l++];
        for (i = head[u]; i != -1; i = g[i].next){
            int v = g[i].v;
            if (level[v] == -1 && g[i].w > eps){
                level[v] = level[u] + 1;
                q[++r] = v;
                if (v == e) return true;
            }
        }
    }
    return false;
}
double find(int s,int e){
    int i;
    double ans = 0;
    int top = 1;

    while (top){
        int u = (top == 1 ? s : g[q[top - 1]].v);//如果没有变肯定是起点,否则就是上一个边终点

        if (u == e){
            double MIN = inf;
            int pos;
            //找出最小流量
            for (i = 1; i < top; ++i){
                int tp = q[i];//注意这里取边的编号
                if (g[tp].w < MIN){
                    MIN = g[tp].w;
                    pos = i;
                }
            }
            //更新容量
            for (i = 1; i < top; ++i){
                int tp = q[i];//注意这里取边的编号
                g[tp].w -= MIN;
                g[tp^1].w += MIN;
            }
            ans += MIN;
            top = pos;
        }
        else{//找可行流
            for (i = head[u]; i != -1; i = g[i].next){
                int v = g[i].v;
                if (g[i].w > eps && level[v] == level[u] + 1){
                    q[top++] = i;
                    break;
                 }
            }
            if (i == -1){//如果u没有可走的子节点
                top--;
                level[u] = -1;
            }
        }
    }
    return ans;
}
double dinic(int s,int e,double mid)
{
    int i;
    //建图是关键
    CL(head,-1); ct = 0;
    for (i =  1; i <= m; ++i)
    {
        int u = t_g[i].u;
        int v = t_g[i].v;
        add(u,v,1.0); add(v,u,1.0);
    }
    for (i = 1; i <= n; ++i)
    {
        add(s,i,m);
        add(i,e,1.0*m + 2*mid - du[i]);
    }
    //求最小割
    double ans = 0;
    while (layer(s,e)) ans += find(s,e);
    return ans;
}
void dfs(int s)
{
    vt[s] = true;
    for (int i = head[s]; i != -1; i = g[i].next)
    {
        int v = g[i].v;
        double w = g[i].w;
        if (!vt[v] &&  w > eps)
        {
            path[len++] = v;
            dfs(v);
        }
    }
}
int main()
{
    //Read();
    int i;
    while (~scanf("%d%d",&n,&m))
    {
        if (m == 0)
        {
            printf("1\n1\n");
            continue;
        }
        CL(du,0);
        for (i = 1; i <= m; ++i)
        {
            scanf("%d%d",&t_g[i].u,&t_g[i].v);
            du[t_g[i].u]++;
            du[t_g[i].v]++;
        }
        double l = 1.0/n;
        double r = m*1.0;
        double mid = 0;
        int s = 0;
        int e = n + 1;
        lim = 1.0/(n*n);
        while (r - l > lim)//证明有:任意两个最大密度子图的差值不会超过1/(n*n)
        {
            mid = (l + r)/2;
            double tmp = dinic(s,e,mid);
            double ans = (m*n - tmp)/2.0;//得到值
            if (ans > eps) l = mid;
            else r = mid;
        }
        dinic(s,e,l);
        CL(vt,false);
        len = 0;
        dfs(s);
        sort(path,path + len);
        printf("%d\n",len);
        for (i = 0; i < len; ++i) printf("%d\n",path[i]);
    }
    return 0;
}

  

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
信息数据从传统到当代,是一直在变革当中,突如其来的互联网让传统的信息管理看到了革命性的曙光,因为传统信息管理从时效性,还是安全性,还是可操作性等各个方面来讲,遇到了互联网时代才发现能补上自古以来的短板,有效的提升管理的效率和业务水平。传统的管理模式,时间越久管理的内容越多,也需要更多的人来对数据进行整理,并且数据的汇总查询方面效率也是极其的低下,并且数据安全方面永远不会保证安全性能。结合数据内容管理的种种缺点,在互联网时代都可以得到有效的补充。结合先进的互联网技术,开发符合需求的软件,让数据内容管理不管是从录入的及时性,查看的及时性还是汇总分析的及时性,都能让正确率达到最高,管理更加的科学和便捷。本次开发的医院后台管理系统实现了病房管理、病例管理、处方管理、字典管理、公告信息管理、患者管理、药品管理、医生管理、预约医生管理、住院管理、管理员管理等功能。系统用到了关系型数据库中王者MySql作为系统的数据库,有效的对数据进行安全的存储,有效的备份,对数据可靠性方面得到了保证。并且程序也具备程序需求的所有功能,使得操作性还是安全性都大大提高,让医院后台管理系统更能从理念走到现实,确确实实的让人们提升信息处理效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值