[SPOJ839]OPTM-Optimal Marks

题意

给你一个无向图G(V,E)。 每个顶点都有一个int范围内的整数的标记。 不同的顶点可能有相同的标记。
对于边(u,v),我们定义Cost(u,v)= mark [u] xor mark [v]。
现在我们知道某些节点的标记了。你需要确定其他节点的标记,以使边的总成本尽可能小。


题解

最小割
发现贡献是异或的形式
所以考虑每一位单独处理
对于第\(w\)
考虑将原图划分成两个集合
一个集合是\(S\)集,另外一个集合是\(T\)
\(S\)集代表这个点这一位是\(1\)
\(T\)集代表这个点这一位是\(0\)
然后将原图中的边连双向边,流量为\(1\)
如果一个点\(u\)的点权已经确定,那么如果这一位为\(1\)就连\(S\to u\),流量为\(INF\),如果这一位为\(0\)就连\(u\to T\),流量为\(INF\)
最后所有在\(S\)集(即\(bfs\)可达的点)这一位都是\(1\)

代码

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
const int M = 605 ;
const int N = 5005 ;
const int INF = 1e9 ;
using namespace std ;

inline int read() {
	char c = getchar() ; int x = 0 , w = 1 ;
	while(c>'9'||c<'0') { if(c=='-') w = -1 ; c = getchar() ; }
	while(c>='0'&&c<='9') { x = x*10+c-'0' ; c = getchar() ; }
	return x*w ;
}

bool vis[M] ;
int n , m , S , T , K , num = 1 ;
int fr[N] , tw[N] , val[M] , hea[M] , ans[M] , dep[M] ;

struct E { int nxt , to , dis ; } edge[N * 5] ;

inline void Bclear() {
	memset(vis , false , sizeof(vis)) ;
	memset(ans , 0 , sizeof(ans)) ;
}
inline void Clear() {
	num = 1 ; 
	memset(hea , 0 , sizeof(hea)) ;
}
inline void Insert_edge(int from , int to , int dis) {
	edge[++num].nxt = hea[from] ;
	edge[num].to = to ;
	edge[num].dis = dis ;
	hea[from] = num ;
}
inline void add_edge(int u , int v , int w) {
	Insert_edge(u , v , w) ;
	Insert_edge(v , u , 0) ;
}
inline bool bfs() {
	queue < int > q ; q.push(S) ;
	memset(dep , 0 , sizeof(dep)) ; dep[S] = 1 ;
	while(!q.empty()) {
		int u = q.front() ; q.pop() ;
		for(int i = hea[u] ; i ; i = edge[i].nxt) {
			int v = edge[i].to ;
			if(!dep[v] && edge[i].dis) {
				dep[v] = dep[u] + 1 ;
				q.push(v) ;
			}
		}
	}
	return dep[T] ;
}
int dfs(int u , int dis) {
	if(u == T || !dis) return dis ; int sum = 0 ;
	for(int i = hea[u] ; i ; i = edge[i].nxt) {
		int v = edge[i].to ;
		if(dep[v] == dep[u] + 1 && edge[i].dis > 0) {
			int diss = dfs(v , min(dis , edge[i].dis)) ;
			if(diss > 0) {
				edge[i].dis -= diss ; edge[i ^ 1].dis += diss ;
				sum += diss ; dis -= diss ; if(!dis) break ;
			}
		}
	}
	if(!sum) dep[u] = -1 ; return sum ;
}
inline void dinic() {
	while(bfs())
		dfs(S , INF) ;
}
int main() {
	int Case = read() ;
	while(Case --) {
		Bclear() ;
		n = read() ; m = read() ;
		for(int i = 1 ; i <= m ; i ++) 
			fr[i] = read() , tw[i] = read() ;
		K = read() ;
		for(int i = 1 , x ; i <= K ; i ++) {
			x = read() ;
			val[x] = read() ;
			vis[x] = true ;
		}
		S = 0 ; T = n + 1 ;
		for(int w = 0 ; w < 31 ; w ++) {
			Clear() ;
			for(int i = 1 , u , v ; i <= m ; i ++) {
				u = fr[i] , v = tw[i] ;
				add_edge(u , v , 1) ;
				add_edge(v , u , 1) ;
			}
			for(int i = 1 ; i <= n ; i ++) {
				if(!vis[i]) continue ;
				if(val[i] & (1 << w))
					add_edge(S , i , INF) ;
				else add_edge(i , T , INF) ;
			}
			dinic() ;
			bfs() ;
			for(int i = 1 ; i <= n ; i ++)
				if(dep[i])
					ans[i] |= (1 << w) ;
		}
		for(int i = 1 ; i <= n ; i ++)
			printf("%d\n",ans[i]) ;
	}
	return 0 ;
}
posted @ 2019-04-26 15:52  beretty  阅读(206)  评论(0编辑  收藏  举报