题目链接

题意

给出n个人,和m对有冲突的人。要裁掉一些人,使得冲突率最高,冲突率为存在的冲突数/人数。

思路

题意可以转化为,求出一些边,使得|E|/|V|最大,这种分数规划叫做最大密度子图。

学习

建图

对于每个边,依赖于点,可以转化为最大权闭合子图来求解。

最大密度子图: max(|E|/|V|)

分数规划

k = |E|/|V|

h(g) = E - V * g

边依赖于点

转化为最大权闭合图

二分点权即g

h(g)为递减函数

当h(g) < 0,不合法,要减小g

当h(g) > 0,说明存在更优解,要增大g

当h(g) = 0,得到最优解

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int N = 1111;
const double eps = 1e-8;
const double inf = 1000000000;
const int INF = 0x3f3f3f3f;
struct Edge {
int u, v, nxt; double cap;
} edge[N*8];
int head[N], tot, dis[N], vis[N], gap[N], pre[N], cur[N], S, T, n, m;
pii p[N];
vector<int> ans;
/*
最大密度子图: max(|E|/|V|)
分数规划
k = |E|/|V|
h(g) = E - V * g
边依赖于点
转化为最大权闭合图
二分点权即g
h(g)为递减函数
当h(g) < 0,不合法,要减小g
当h(g) > 0,说明存在更优解,要增大g
当h(g) = 0,得到最优解
*/ void Add(int u, int v, double cap) {
edge[tot] = (Edge) { u, v, head[u], cap }; head[u] = tot++;
edge[tot] = (Edge) { v, u, head[v], 0 }; head[v] = tot++;
} void BFS(int T) {
queue<int> que;
memset(dis, INF, sizeof(dis));
memset(gap, 0, sizeof(gap));
dis[T] = 0; gap[0]++; que.push(T);
while(!que.empty()) {
int u = que.front(); que.pop();
for(int i = head[u]; ~i; i = edge[i].nxt) {
int v = edge[i].v;
if(dis[v] == INF) {
dis[v] = dis[u] + 1;
gap[dis[v]]++;
que.push(v);
}
}
}
} double ISAP(int S, int T, int n) {
BFS(T);
memcpy(cur, head, sizeof(cur));
int u = pre[S] = S, index, i;
double flow, ans = 0;
while(dis[S] < n) {
if(u == T) {
flow = inf; index = u;
for(u = S; u != T; u = edge[cur[u]].v)
if(flow > edge[cur[u]].cap) flow = edge[cur[u]].cap, index = u;
for(u = S; u != T; u = edge[cur[u]].v)
edge[cur[u]].cap -= flow, edge[cur[u]^1].cap += flow;
ans += flow; u = index;
}
for(i = cur[u]; ~i; i = edge[i].nxt)
if(dis[edge[i].v] == dis[u] - 1 && edge[i].cap > 0) break;
if(~i) {
cur[u] = i; pre[edge[i].v] = u; u = edge[i].v;
} else {
int md = n + 1;
if(--gap[dis[u]] == 0) break;
for(i = head[u]; ~i; i = edge[i].nxt)
if(dis[edge[i].v] < md && edge[i].cap > 0)
md = dis[edge[i].v], cur[u] = i;
gap[dis[u] = md + 1]++;
u = pre[u];
}
}
return ans;
} void Build(double g) {
memset(head, -1, sizeof(head)); tot = 0;
for(int i = 1; i <= n; i++) Add(i, T, g);
for(int i = 1; i <= m; i++) {
Add(S, i + n, 1);
Add(i + n, p[i].first, inf);
Add(i + n, p[i].second, inf);
}
} void DFS(int u) {
for(int i = head[u]; ~i; i = edge[i].nxt) {
int v = edge[i].v;
if(edge[i].cap > 0 && !vis[v]) {
vis[v] = 1; DFS(v);
if(1 <= v && v <= n) ans.push_back(v);
}
}
} int main() {
while(~scanf("%d%d", &n, &m)) {
for(int i = 1; i <= m; i++) scanf("%d%d", &p[i].first, &p[i].second);
if(m == 0) { puts("1\n1"); continue; }
S = 0, T = n + m + 1;
double l = 0.0, r = m;
while(r - l >= 1.0 / n / n) { // 不同解之间误差的精度不超过1/(n*n)
double mid = (l + r) / 2;
Build(mid);
double now = 1.0 * m - ISAP(S, T, T + 1); // 转化为最大权闭合图
if(now < eps) r = mid; // h(g)为单调递减函数,如果h(g)<0,那么g要减小,当h(g)为0得到最优解
else l = mid;
}
Build(l);
ISAP(S, T, T + 1);
ans.clear();
vis[S] = 1;
memset(vis, 0, sizeof(vis));
DFS(S);
sort(ans.begin(), ans.end());
printf("%d\n", ans.size());
for(int i = 0; i < ans.size(); i++)
printf("%d\n", ans[i]);
}
return 0;
} /*
5 6
1 5
5 4
4 2
2 5
1 2
3 1 4 0
---
4
1
2
4
5 1
1
*/

POJ 3155:Hard Life(最大密度子图)的更多相关文章

  1. POJ 3155 Hard Life 最大密度子图 最大权闭合图 网络流 二分

    http://poj.org/problem?id=3155 最大密度子图和最大权闭合图性质很相近(大概可以这么说吧),一个是取最多的边一个是取最多有正贡献的点,而且都是有选一种必须选另一种的限制,一 ...

  2. POJ 3155 Hard Life(最大密度子图+改进算法)

    Hard Life Time Limit: 8000MS   Memory Limit: 65536K Total Submissions: 9012   Accepted: 2614 Case Ti ...

  3. POJ 3155 Hard Life(最大密度子图)

    裸题.输入一个无向图,输出最大密度子图(输出子图结点数和升序编号). 看了<最小割模型在信息学竞赛中的应用——胡伯涛>的一部分,感觉01分数规划问题又是个大坑.暂时还看不懂. 参考http ...

  4. poj 3155 最大密度子图

    思路: 这个还是看的胡伯涛的论文<最小割在信息学竞赛中的应用>.是将最大密度子图问题转化为了01分数规划和最小割问题. 直接上代码: #include <iostream> # ...

  5. POJ 3155 Hard Life

    Hard Life Time Limit: 8000ms Memory Limit: 65536KB This problem will be judged on PKU. Original ID:  ...

  6. POJ3155 Hard Life [最大密度子图]

      题意:最大密度子图 #include<iostream> #include<cstdio> #include<cstring> #include<algo ...

  7. poj3155 最大密度子图

    求最大密度子图 记得在最后一次寻找的时候记得将进入的边放大那么一点点,这样有利于当每条边都满流的情况下会选择点 #include <iostream> #include <algor ...

  8. bzoj 1312 最大密度子图

    晕,m=0是要输出1(弄的我还找管理员要数据,但明显题意是叫我们输出0呀) 最大密度子图,把边转换成点,然后二分答案,跑最大权闭合子图判定是否可行. #include <cstdio> # ...

  9. 2017 计蒜之道 初赛 第三场 D. 腾讯狼人杀 (点边都带权的最大密度子图)

    点边都带权的最大密度子图,且会有必须选的点. 求\(\frac{\sum w_e}{k*(2n-k)}\)的最大值,其中k为子图点数 设\[h(g) = \sum w_e - g*(2nk-k^2)\ ...

随机推荐

  1. MVVM讲解

    一,MVVM理论知识 从上一篇文章中,我们已经知道,WPF技术的主要特点是数据驱动UI,所以在使用WPF技术开发的过程中是以数据为核心的,WPF提供了数据绑定机制,当数据发生变化时,WPF会自动发出通 ...

  2. DLL编写与调用全解

    DLL编写与调用全解 DELPHI学习   2008-12-23 22:52   阅读8   评论0   字号: 大  中  小 第一章 为什么要使用动态链接库(DLL) top 提起DLL您一定不会 ...

  3. 图像滤镜艺术---微软自拍APP滤镜实现合集DEMO

    原文:图像滤镜艺术---微软自拍APP滤镜实现合集DEMO 微软最近推出了自家的美颜app,大家有兴趣可以在苹果商店中下载一下看一看,今天,我们要说的便是这款app中的所有滤镜实现问题. 这款app中 ...

  4. Win8 Metro(C#)数字图像处理--2.60部分彩色保留算法

    原文:Win8 Metro(C#)数字图像处理--2.60部分彩色保留算法  [函数名称]   部分彩色保留函数       WriteableBitmap PartialcolorProcess ...

  5. Win10《芒果TV》商店版更新v3.2.5:新增会员频道,修复多处细节问题,小年快乐

    听因乐不凡,尽在芒果TV,湖南卫视大型音乐竞技节目<歌手>,每周六晚22:30在芒果TV与湖南卫视同步直播,1月20日周五晚七点半,2016-2017湖南卫视<小年夜春晚>会员 ...

  6. 分享基于.NET动态编译&Newtonsoft.Json封装实现JSON转换器(JsonConverter)原理及JSON操作技巧

    看文章标题就知道,本文的主题就是关于JSON,JSON转换器(JsonConverter)具有将C#定义的类源代码直接转换成对应的JSON字符串,以及将JSON字符串转换成对应的C#定义的类源代码,而 ...

  7. Delphi的Anymouse方法探秘

    匿名函数是用Interface来实现的,具体细节可以看http://www.raysoftware.cn/?p=38匿名函数还是非常方便的.比如自己封装的异步调用.Async(procedure(AP ...

  8. 在DBGrid增加一列CheckBox(而非DBCheckBox)

    自:http://rabbitfox.blog.sohu.com/33264033.html http://community.csdn.net/Expert/topic/5342/5342920.x ...

  9. mysql自动安装教程说明

    这里只说明了思路和方法 我们在安装程序里面可能需要安装的时候将mysql一起安装,那么我们就按照下面的顺序思路来. 首先我们安装的电脑上可能已经安装了mysql,所以我们的mysql服务就起一个名字, ...

  10. 一个拼图工具TImageBox的制作思路

    http://www.cnblogs.com/del/archive/2010/04/24/1719631.html