现在的位置: 首页 > 综合 > 正文

Hard Life poj3155

2014年01月29日 ⁄ 综合 ⁄ 共 4097字 ⁄ 字号 评论关闭

最大密度子图,论文题目。 

这题构造出来的g(k) = max{∑E-k∑V},g(k)是一个下界为0的单调递减函数,即存在x1, g(x1) = 0,

对于所有x > x1, g(x)≡0。按照论文上的证明方法的话我们只要发现一个g(k) = 0,就可以认为是最

优解了,但是此题要二分到函数值为0的左端点才可以,为什么是这样呢?

其实我们不难发现对于所有的x > x1, 我们采取的最优决策是一个都不选,这就会导致∑V为0,而我

们证明其最优性时的前提是∑V不为0,所以这种情况我们得到的并不是最优解。

还有一个问题就是我们求最大闭合权图的算法会导致一种情况,当全部收益值与耗费值相等时,我们

使用dfs求决策时,会导致什么不选择任何决策,如果单纯的求最大闭合权图,这种做法没有问题,

但是对于这题要求V不能为∅,所以我们可以选择一个x2 < x1,且x1-x2 < 1/(n*n),对x2再求一次决策,

根据论文上的证明x2也会得到最优解,并且不会导致V为∅的情况。

测试数据:

input:

3 3

1 2

2 3

1 3

output:

3

1

2

3

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <queue>
#include <algorithm>
#include <vector>
#include <cstring>
#include <stack>
#include <cctype>
#include <utility>   
#include <map>
#include <string>  
#include <climits> 
#include <set>
#include <string>    
#include <sstream>
#include <utility>   
#include <ctime>
#include <bitset>
#include <iomanip>
//#pragma comment(linker, "/STACK:102400000,102400000")

using std::priority_queue;
using std::vector;
using std::swap;
using std::stack;
using std::sort;
using std::max;
using std::min;
using std::pair;
using std::map;
using std::string;
using std::cin;
using std::cout;
using std::set;
using std::queue;
using std::string;
using std::stringstream;
using std::make_pair;
using std::getline;
using std::greater;
using std::endl;
using std::multimap;
using std::deque;
using std::unique;
using std::lower_bound;
using std::random_shuffle;
using std::bitset;
using std::upper_bound;
using std::multiset;
using std::ios;
using std::make_heap;
using std::push_heap;
using std::pop_heap;

typedef long long LL;
typedef unsigned long long ULL;
typedef unsigned UN;
typedef pair<ULL, ULL> PAIR;
typedef multimap<int, int> MMAP;
typedef long double LF;

const int MAXN(1510);
const int MAXM(40010);
const int MAXE(10010);
const int MAXK(6);
const int HSIZE(13131);
const int SIGMA_SIZE(26+11);
const int MAXH(18);
const int INFI((INT_MAX-1) >> 1);
const ULL BASE(31);
const LL LIM(1e13);
const int INV(-10000);
const int MOD(1000000007);
const double EPS(1e-7);
const LF PI(acos(-1.0));

template<typename T> inline bool checkmax(T &a, T b){if(b > a) { a = b; return true;} return false;}
template<typename T> inline bool checkmin(T &a, T b){if(b < a) { a = b; return true;} return false;}
template<typename T> inline T ABS(const T &a){return a < 0? -a: a;}
inline bool EZ(double a){return ABS(a) < EPS;}

struct EDGE
{
	int u, v, next;
	double lf;
	EDGE(){}
	EDGE(int u_, int v_, double l_, int n_): u(u_), v(v_), lf(l_), next(n_){}
} edge[MAXE];
int first[MAXN], rear;
void init(int n)
{
	memset(first, -1, sizeof(first[0])*(n+1));
	rear = 0;
}

void insert(int u, int v, double lf)
{
	edge[rear] = EDGE(u, v, lf, first[u]);
	first[u] = rear++;
	edge[rear] = EDGE(v, u, 0, first[v]);
	first[v] = rear++;
}

int S, E, N;
int que[MAXN], front, back;
int level[MAXN];

bool bfs()
{
	memset(level, -1, sizeof(level[0])*(N+1));
	front = back = 0;
	que[back++] = S;
	level[S] = 0;
	while(front < back)
	{
		int u = que[front++], v;
		for(int i = first[u]; ~i; i = edge[i].next)
			if(!EZ(edge[i].lf) && level[v = edge[i].v] == -1)
			{
				level[v] = level[u]+1;
				if(v == E) return true;
				que[back++] = v;
			}
	}
	return false;
}

int sta[MAXN], tfi[MAXN], ted[MAXN];
int top;
double aug()
{
	double ret = 0;
	for(int i = 0; i <= N; ++i) tfi[i] = first[i];
	top = 0;
	sta[top++] = S;
	while(top)
	{
		int u = sta[top-1];
		if(u != E)
		{
			int ti;
			for(; ~(ti = tfi[u]); tfi[u] = edge[ti].next)
				if(!EZ(edge[ti].lf) && level[edge[ti].v] == level[u]+1)
					break;
			if(~ti)
			{
				sta[top] = edge[ti].v;
				ted[top++] = ti;
			}
			else
			{
				level[u] = -1;
				--top;
			}
		}
		else
		{
			double mf = INFI;
			for(int i = top-1; i >= 1; --i) checkmin(mf, edge[ted[i]].lf);
			for(int i = top-1; i >= 1; --i)
			{
				edge[ted[i]].lf -= mf;
				edge[ted[i]^1].lf += mf;
				if(EZ(edge[ted[i]].lf)) top = i-1;
			}
			ret += mf;
		}
	}
	return ret;
}

double dinic()
{
	double ret = 0;
	while(bfs()) ret += aug();
	return ret;
}

int rec[1010][2];
double cal(double val, int n, int m)
{
	N = n+m+2;
	S = N-2;
	E = N-1;
	init(N);
	double ret = m;
	for(int i = 0; i < m; ++i) 
	{
		insert(S, i, 1);
		insert(i, rec[i][0]+m, INFI);
		insert(i, rec[i][1]+m, INFI);
	}
	for(int i = 0; i < n; ++i) insert(i+m, E, val);
	return ret-dinic();
}

bool vis[MAXN];
void dfs(int u)
{	
	vis[u] = true;
	for(int i = first[u]; ~i; i = edge[i].next)
		if(!EZ(edge[i].lf) && !vis[edge[i].v])
			dfs(edge[i].v);
}

int main()
{
	int n, m;
	while(~scanf("%d%d", &n, &m))
	{	
		for(int i = 0; i < m; ++i)
		{
			scanf("%d%d", rec[i], rec[i]+1);
			--rec[i][0];
			--rec[i][1];
		}
		double l = 0, r = n, lim = 1./n/n;
		while(r-l >= lim)
		{
			double mid = (l+r)/2;
			if(cal(mid, n, m) > 0) l = mid;
			else r = mid;
		}
		cal(l, n, m);  //mid-l < 1/(n*n)
		memset(vis, 0, sizeof(vis));
		dfs(S);
		int ans = 0;
		for(int i = 0; i < n; ++i)
			if(vis[i+m])
				++ans;
		if(!EZ(l))
		{
			printf("%d\n", ans);
			for(int i = 0; i < n; ++i)
				if(vis[i+m])
					printf("%d\n", i+1);
		}
		else
			printf("1\n1\n");
	}
	return 0;
}


抱歉!评论已关闭.