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)\ ...
随机推荐
- UWP 应用中的Back button(TitleBar) 的处理
后退按钮是一项系统提供的 UI 提示,可以在后退堆栈或用户导航历史记录中支持向后导航. 用起来其实也是很简单的,只需要在App.xaml.cs 中修改(添加)如下红色代码,便可实现.. sealed ...
- window下nodejs爬取gb2312网页出现乱码的解决方案
发布于 2012-8-22 18:15 5230 次浏览 最后一次编辑是 2013-2-18 22:31 linux环境下,我们可以通过 iconv 这个C++模块来处理Node.JS不支持的字 ...
- asp .net core 读取读取Views文件夹下的js和css
//读取Views文件夹下的js和css app.UseStaticFiles(new StaticFileOptions() { FileProvider = new PhysicalFilePro ...
- socket函数集-----网络编程必备值得拥有
accept(接受socket连线) 相关函数 socket,bind,listen,connect 表头文件 #include<sys/types.h> #include<sys/ ...
- explicit:C++规定,当定义了只有一个参数的构造函数时,同时也定义了一种隐式的类型转换
explicit研究 explicit是C++中的关键字,不是C语言中的.英文直译是“明确的”.“显式的”意思.出现这个关键字的原因,是在C++中有这样规定的基础上:当定义了只有一个参数的构造函数 ...
- 如何将JPEG缩略图放到LISTVIEW中(delphi listview自绘图形)
http://www.docin.com/p-567657457.html?qq-pf-to=pcqq.c2c http://www.cnblogs.com/snow001x/archive/2008 ...
- Sublime text追踪函数插件:ctags[转载]
一.下载(择其一即可): 1)http://ctags.sourceforge.net/ 2)http://prdownloads.sourceforge.net/ctags/ 解压后单独取出ctag ...
- 微信小程序把玩(十四)button组件
原文:微信小程序把玩(十四)button组件 button按钮用的算是最普遍的组件之一. 主要属性: wxml <!--按钮默认样式,点击事件--> <button type=&qu ...
- Ubuntu 搭建 GitLab 笔记
简介 GitLab 社区版可以提供许多与 GitHub 相同的功能,且部署在属于自己的机器上,我们会因为网络及其他一些问题而不便使用 GitHub ,这时部署一个 GitLab 是最好的选择. 下载 ...
- 微信小程序把玩(三十八)获取设备信息 API
原文:微信小程序把玩(三十八)获取设备信息 API 获取设备信息这里分为四种, 主要属性: 网络信息wx.getNetWorkType, 系统信息wx.getSystemInfo, 重力感应数据wx. ...