题目链接

题意

给出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. springboot 集成单元测试

    官网参考地址 1. 添加依赖 <!-- 测试 --> <dependency> <groupId>org.springframework.boot</grou ...

  2. Emgu-WPF 激光雷达研究-绘制雷达图

    原文:Emgu-WPF 激光雷达研究-绘制雷达图 硬件:Hokuyo URG04LX 环境:VS2017- win10- 64  Emgu_3.2.0.2682 语言:C#  WPF   数据解析参考 ...

  3. 第0001题 : 产生随机数(顺便读random模块官方文档)

    看这个之前我准备先看一下random模块的官方文档... 在整个随机模块中,  最基础的就是random, 它产生一个 [0.0, 1.0)的浮点数. 这个模块下所有的函数实际上是绑定在一个叫做ran ...

  4. FileHelper

    using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Win ...

  5. Win8 Metro(C#)数字图像处理--3.2图像方差计算

    原文:Win8 Metro(C#)数字图像处理--3.2图像方差计算 /// <summary> /// /// </summary>Variance computing. / ...

  6. layui打印表格自定义函数

    函数如下 function print (tablelayid) { var v = document.createElement("div"); var f = ["& ...

  7. 关于这次KPL春季决赛的感悟

    QG 4:0 横扫AG超玩会,关于这一点想写一些自己的感悟,AG超玩会一直都是 4:0 横扫别人,这次在冠军赛被别人横扫,一点喘息的机会都没有.   1.QGhappy 跟本没把AG超玩会放在眼里,很 ...

  8. uni-app中vue组件父子值传递

    一.父组件向子组件传递数据(props) <template> <view class="container" style="background: # ...

  9. shell多线程之进程间通信

    # 这是一个简单的并发程序,有如下要求: # .有两个程序a和b,希望他们能并发执行,以节约时间 # .a和b都是按照日期顺序执行,但b每日程序的前提条件是当日a的程序已经执行完毕 #解决方案: # ...

  10. 高并发 Nginx+Lua OpenResty系列(10)——商品详情页

    本章以京东商品详情页为例,京东商品详情页虽然仅是单个页面,但是其数据聚合源是非常多的,除了一些实时性要求比较高的如价格.库存.服务支持等通过AJAX异步加载加载之外,其他的数据都是在后端做数据聚合然后 ...