【bzoj4316】小C的独立集

4316: 小C的独立集

Time Limit: 10 Sec   Memory Limit: 128 MB
Submit: 472   Solved: 263
[ Submit][ Status][ Discuss]

Description

图论小王子小C经常虐菜,特别是在图论方面,经常把小D虐得很惨很惨。
这不,小C让小D去求一个无向图的最大独立集,通俗地讲就是:在无向图中选出若干个点,这些点互相没有边连接,并使取出的点尽量多。
小D虽然图论很弱,但是也知道无向图最大独立集是npc,但是小C很仁慈的给了一个很有特点的图: 图中任何一条边属于且仅属于一个简单环,图中没有重边和自环。小C说这样就会比较水了。
小D觉得这个题目很有趣,就交给你了,相信你一定可以解出来的。

Input

第一行,两个数n, m,表示图的点数和边数。
第二~m+1行,每行两个数x,y,表示x与y之间有一条无向边。

Output

输出这个图的最大独立集。

Sample Input

5 6
1 2
2 3
3 1
3 4
4 5
3 5

Sample Output

2

HINT

100% n <=50000, m<=60000


Source

[ Submit][ Status][ Discuss]

仙人掌DP。。。。。
因为求点双GG调了好久
具体做法就是在方点上枚举父亲选还是不选做环形dp,在圆点上直接把方点的贡献加起来就好了


代码:
#include<cstdio>
#include<ctime>
#include<cstdlib>
#include<vector>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;

typedef long long LL;

const int INF = 2147483647;
const int maxn = 50010 * 2;

vector<int> e[maxn],ei[maxn];
int n,m,tot,ans,fa[maxn];
int g[maxn][2],f[maxn][2];
int stk[maxn],top,low[maxn],dfn[maxn],tme,rec[maxn];
int tmp[maxn],vis[maxn];

inline int getint()
{
	int ret = 0;
	char c = getchar();
	while (c < '0' || '9' < c) c = getchar();
	while ('0' <= c && c <= '9')
		ret = ret * 10 + c - '0',c = getchar();
	return ret;
}

inline void tarjan(int u,int fa)
{
	stk[++top] = u;
	dfn[u] = low[u] = ++tme;
	for (int i = 0; i < ei[u].size(); i++)
	{
		int v = ei[u][i];
		if (v == fa) continue;
		if (!dfn[v])
		{
			tarjan(v,u);
			low[u] = min(low[u],low[v]);
			if (dfn[u] <= low[v])
			{
				int all = 0;
				++tot;
				
				while (low[stk[top]] >= dfn[u] && u != stk[top])
				{
					int p = stk[top--];
					e[p].push_back(tot);
					e[tot].push_back(p);
					all++;
				}
				e[u].push_back(tot);
				e[tot].push_back(u);
				all++;	
/*				if (all > 2)
				{
					printf("u : %d",u);
					for (int i = 1; i <= all; i++)
						tmp[i] = e[tot][i - 1];
					putchar('\n');
					for (int i = 1; i <= all; i++)
						printf("%d ",tmp[i]);
					printf("\ndfn\n");
					for (int i = 1; i <= all; i++)
						printf("%d ",dfn[tmp[i]]);
					printf("\nlow\n");
					for (int i = 1; i <= all; i++)
						printf("%d ",low[tmp[i]]);
					putchar('\n');
					for (int i = 1; i <= all; i++)
					{
						printf("%d : ",tmp[i]);
						for (int j = 0; j < ei[tmp[i]].size(); j++)
							printf("%d ",ei[tmp[i]][j]);
						putchar('\n');
					}
					putchar('\n');
				}
*/				rec[tot] = 1;
			}
		}
		else low[u] = min(low[u],dfn[v]);
	}
}

inline void trans(int now)
{
	for (int i = 2; i <= now; i++)
	{
		g[i][0] = max(g[i - 1][1] , g[i - 1][0]) + (now == i ? 0 : f[tmp[i]][0]);
		g[i][1] = g[i - 1][0] + (now == i ? 0 : f[tmp[i]][1]);
	}
}

inline void clear(int now)
{
	for (int i = 1; i <= now; i++) g[i][0] = g[i][1] = 0;
}

inline void dp(int u)
{
	int pos,now = 0;
	for (int i = 0; i < e[u].size(); i++)
	{
		int v = e[u][i];
		if (fa[u] == v)
		{
			pos = i;
			break;
		}
	}
	for (int i = pos + 1; i < e[u].size(); i++)
		tmp[++now] = e[u][i];
	for (int i = 0; i <= pos; i++)
		tmp[++now] = e[u][i];
	
	
	clear(now);
	g[1][1] = f[tmp[1]][1]; g[1][0] = f[tmp[1]][0];
	trans(now);
	f[u][0] = g[now][0];
	
	clear(now);
	g[1][1] = -INF; g[1][0] = f[tmp[1]][0];
	trans(now);
	f[u][1] = g[now][1];
}

inline void Dp(int u)
{
	if (!rec[u]) f[u][1]++;
	vis[u] = 1;
	for (int i = 0; i < e[u].size(); i++)
	{
		int v = e[u][i];
		if (v == fa[u]) continue;
		fa[v] = u;
		Dp(v);
		if (!rec[u]) 
			f[u][0] += f[v][0] , f[u][1] += f[v][1];
	}
	if (rec[u]) dp(u);
}

int main()
{
	#ifdef AMC
		freopen("AMC1.txt","r",stdin);
		freopen("AMC2.txt","w",stdout);
	#endif 
	n = getint(); m = getint();
	for (int i = 1; i <= m; i++)
	{
		int u = getint(),v = getint();
		ei[u].push_back(v);
		ei[v].push_back(u);
	}
	tot = n;
	for (int i = 1; i <= n; i++)
		if (!dfn[i])
			tarjan(i,0);

	for (int i = 1; i <= tot; i++)
		if (!vis[i])
		{
			Dp(i);
			ans += max(f[i][0],f[i][1]);
		}
	printf("%d",ans);

	return 0;
}

猜你喜欢

转载自blog.csdn.net/joky_2002/article/details/80332669