POJ 3155:Hard Life(最大密度子图)
题意
给出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(最大密度子图)的更多相关文章
- POJ 3155 Hard Life 最大密度子图 最大权闭合图 网络流 二分
http://poj.org/problem?id=3155 最大密度子图和最大权闭合图性质很相近(大概可以这么说吧),一个是取最多的边一个是取最多有正贡献的点,而且都是有选一种必须选另一种的限制,一 ...
- POJ 3155 Hard Life(最大密度子图+改进算法)
Hard Life Time Limit: 8000MS Memory Limit: 65536K Total Submissions: 9012 Accepted: 2614 Case Ti ...
- POJ 3155 Hard Life(最大密度子图)
裸题.输入一个无向图,输出最大密度子图(输出子图结点数和升序编号). 看了<最小割模型在信息学竞赛中的应用——胡伯涛>的一部分,感觉01分数规划问题又是个大坑.暂时还看不懂. 参考http ...
- poj 3155 最大密度子图
思路: 这个还是看的胡伯涛的论文<最小割在信息学竞赛中的应用>.是将最大密度子图问题转化为了01分数规划和最小割问题. 直接上代码: #include <iostream> # ...
- POJ 3155 Hard Life
Hard Life Time Limit: 8000ms Memory Limit: 65536KB This problem will be judged on PKU. Original ID: ...
- POJ3155 Hard Life [最大密度子图]
题意:最大密度子图 #include<iostream> #include<cstdio> #include<cstring> #include<algo ...
- poj3155 最大密度子图
求最大密度子图 记得在最后一次寻找的时候记得将进入的边放大那么一点点,这样有利于当每条边都满流的情况下会选择点 #include <iostream> #include <algor ...
- bzoj 1312 最大密度子图
晕,m=0是要输出1(弄的我还找管理员要数据,但明显题意是叫我们输出0呀) 最大密度子图,把边转换成点,然后二分答案,跑最大权闭合子图判定是否可行. #include <cstdio> # ...
- 2017 计蒜之道 初赛 第三场 D. 腾讯狼人杀 (点边都带权的最大密度子图)
点边都带权的最大密度子图,且会有必须选的点. 求\(\frac{\sum w_e}{k*(2n-k)}\)的最大值,其中k为子图点数 设\[h(g) = \sum w_e - g*(2nk-k^2)\ ...
随机推荐
- MATLAB利用散点进行函数曲线拟合
原文:MATLAB利用散点进行函数曲线拟合 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/laobai1015/article/details/77 ...
- VMware Workstation克隆linux虚拟机操作
1.删除MAC地址,修改IP [root@xuegod63 network-scripts]# vim ifcfg-eth0 [root@xuegod63 network-scripts]# cat ...
- style原则问题
就近原则 1.“行内”覆盖“嵌入”,“嵌入”覆盖“外部”Style.xml <Window.Resources> <Grid.Resources> ….中间层 <Butt ...
- php将两个数组相同的key合并到一个数组
$arr = array( array( 'id' => 1, 'user_name'=>'test1' ), array( 'id' =& ...
- GIS基础软件及操作(五)
原文 GIS基础软件及操作(五) 练习五.空间分析的基本操作 空间分析的基本操作 空间分析模块 空间分析是基于地理对象的位置和形态的空间数据的分析技术,其目的在于提取和传输空间信息.空间分析是地理信息 ...
- ArcGIS for Desktop入门教程_第五章_ArcCatalog使用 - ArcGIS知乎-新一代ArcGIS问答社区
原文:ArcGIS for Desktop入门教程_第五章_ArcCatalog使用 - ArcGIS知乎-新一代ArcGIS问答社区 1 ArcCatalog使用 1.1 GIS数据 地理信息系统, ...
- 跨平台网络通信与服务器框架 acl 3.2.0 发布,acl_cpp 是基于 acl 库的 C++ 库
acl 3.2.0 版本发布了,acl 是 one advanced C/C++ library 的简称,主要包括网络通信库以及服务器框架库等功能,支持 Linux/Windows/Solaris/F ...
- flask相关使用
一.手动创建一个干净的含有蓝图的flask项目目录 在init.py中 from flask import Flaskmy_app=Flask(__name__)def create_app() ...
- java高级知识
1. Spring读取配置文件的流程,怎样引入注解? 2. Spring是怎么注入新的java文件的? 3. CAS锁是什么实现机制,在java的哪些包里最常使用?什么情况下会使用CAS锁? 4. 线 ...
- Java基础(四) StringBuffer、StringBuilder原理浅析
StringBuilder与StringBuffer作用就是用来处理字符串,但String类本身也具备很多方法可以用来处理字符串,那么为什么还要引入这两个类呢? 关于String的讲解请看Java基础 ...