bzoj1006(弦图最大势)

对一个图进行染色,要求每一条边相连的两个点都是异色的。求所用到颜色的最小数量。

此题保证图为一个弦图(周长>=4的环中间一定有一条弦),使用最大势算法。

最大势:

最初所有点的值都是0。做n次,每次找出值最大的一个点p(如果有多个就任意),把与之相连的点都+1,然后删除p(p的值要保留)。

做完后,答案就是所有点的分值中出现过的不同的数字的个数。

由于复杂度太大,必须要优化。考虑到最多分值到n-1,于是建一个deque(网上说是链表,但是链表好难写的,原理相同就行),deque[i]存储——值为i的所有点的编号。

每次更新点时只需要把这个新的点加入到另一个队列即可,并不需要删点。因为我们在选取当前点now的时候,会把那些已经遍历过的点pop掉。(类比dijkstra)

维护一个best保留目前的最大分值,如果把deque[best]都pop空了,那么--best;

上代码:

#include <cstdio>
#include <deque>
#include <algorithm>
#include <cstring>
#define N 11000
#define M 1100000
using namespace std;
struct EDGE {
	int to, next;
}edge[2*M];
bool v[N];
int head[N], num[N];
int n, m, cnt;
inline int read() {
	int x = 0, f = 1; char c = getchar();
	while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
	while(c >= '0' && c <= '9') {x = x * 10 + c - 48; c = getchar();}
	return x * f;
}
inline void add(int u, int v) {
	edge[++cnt].to = v;
	edge[cnt].next = head[u]; head[u] = cnt;
	return ;
}
inline void solve() {
	deque<int>Q[N];
	memset(num, 0, sizeof(num));
	memset(v, false, sizeof(v));
	int best = 0;
	for(int i = 1; i <= n; ++i) Q[0].push_back(i);
	int ans;
	while(1) {
		while(!Q[best].empty() && v[Q[best].front()]) Q[best].pop_front();
		if(Q[best].empty()) {if(best == 0) {sort(num+1,num+n+1); int last = -1; ans = 0; for(int i = 1; i <= n; ++i) if(num[i] != last){++ans; last = num[i];} printf("%d", ans); return ;} --best; continue;}
		int now = Q[best].front();
		Q[best].pop_front(); v[now] = true;
		for(int i = head[now]; i; i = edge[i].next) {
			int y = edge[i].to;
			if(v[y]) continue;
			num[y]++;
			best = max(best, num[y]);
			Q[num[y]].push_front(y);
		}
		ans = num[now];
	}
	return ;
}
int main() {
	freopen("1006.in", "r", stdin);
	n = read(); m = read();
	memset(head, 0, sizeof(head)); cnt = 0;
	for(int i = 1; i <= m; ++i) {
		int x = read(), y = read();
		add(x, y); add(y, x);
	}
	solve();
	return 0;
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值