SPOJ839 OPTM - Optimal Marks

传送门

闵神讲网络流应用的例题,来水一水

要写出这道题,需要深入理解两个概念,异或和最小割。

异或具有相对独立性,所以我们把每一位拆开来看,即做大概$32$次最小割。然后累加即可。

然后是最小割把一张图分割成两个集合,简单看就是0集合和1集合。

简单的建图:

原图不变,改成双向边,所有的流量限制为1。然后所有S点向点权为1的连边,点权为0的向T连边,容量都是正无穷。

为什么这样建?首先看,最小割把一张图分成两个点集。而因为我们的流量限制可以让最小割只割真实存在的边,而割的也只有可能是跨越0集合和1集合的边。所以最后的最小割就是答案。

//SPOJ839
//by Cydiater
//2017.1.15
#include <iostream>
#include <cmath>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <iomanip>
#include <queue>
#include <map>
#include <algorithm>
#include <cstring>
#include <string>
#include <bitset>
#include <set>
#include <vector>
using namespace std;
#define ll long long
#define up(i,j,n)	for(int i=j;i<=n;i++)
#define down(i,j,n)	for(int i=j;i>=n;i--)
#define cmax(a,b)	a=max(a,b)
#define cmin(a,b)	a=min(a,b)
#define Auto(i,node)	for(int i=LINK[node];i;i=e[i].next)
#define vci 		vector<int>
const int MAXN=1e4+5;
const int oo=0x3f3f3f3f;
inline int read(){
	char ch=getchar();int x=0,f=1;
	while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-1;ch=getchar();}
	while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
	return x*f;
}
int LINK[MAXN],len=0,N,M,Val[MAXN],TT,Q,tag[MAXN],S,T,ans=0,q[MAXN],head,tail,level[MAXN];
bool used[MAXN],vis[MAXN];
vci E[MAXN];
struct edge{
	int x,y,next,flow,reverse;
}e[MAXN<<1];
namespace solution{
	void Clear(){
		len=0;
		memset(LINK,0,sizeof(LINK));
	}
	inline void insert(int x,int y,int flow,int delta){
		e[++len].next=LINK[x];LINK[x]=len;e[len].y=y;
		e[len].flow=flow;e[len].reverse=len+delta;
	}
	void Prepare(){
		Clear();
		N=read();M=read();
		S=N+1;T=N+2;
		up(i,1,N)E[i].clear();
		up(i,1,M){
			int x=read(),y=read();
			E[x].push_back(y);
			E[y].push_back(x);
		}
		Q=read();
		memset(Val,0,sizeof(Val));
                memset(used,0,sizeof(used));
		while(Q--){
			int node=read(),val=read();
			Val[node]=val;used[node]=1;
		}
	}
	void Build(){
		Clear();
		up(i,1,N){
			int siz=E[i].size();
			up(j,0,siz-1){
				insert(i,E[i][j],1,1);
				insert(E[i][j],i,0,-1);
			}
		}
		up(i,1,N){
			if(tag[i]==1){
				insert(S,i,oo,1);
				insert(i,S,0,-1);
			}else if(tag[i]==0){
				insert(i,T,oo,1);
				insert(T,i,0,-1);
			}
		}
	}
	bool makelevel(){
		memset(level,-1,sizeof(level));
		head=1;tail=0;level[S]=0;q[++tail]=S;
		for(;head<=tail;head++){
			int node=q[head];
			Auto(i,node)if(e[i].flow>0&&level[e[i].y]==-1){
				level[e[i].y]=level[node]+1;
				q[++tail]=e[i].y;
			}
		}
		return level[T]!=-1;
	}
	int addflow(int node,int flow){
		if(node==T)	return flow;
		int maxflow=0,d=0;
		Auto(i,node)if(level[e[i].y]==level[node]+1&&e[i].flow>0){
			if(d=addflow(e[i].y,min(e[i].flow,flow-maxflow))){
				maxflow+=d;
				e[i].flow-=d;
				e[e[i].reverse].flow+=d;
			}
		}
		if(maxflow==0)level[node]=-1;
		return maxflow;
	}
	void Dinic(int dig){
		int d;
		while(makelevel())
			while(d=addflow(S,oo))
				ans+=(d<<dig);
	}
	void DFS(int node){
		vis[node]=1;tag[node]=1;
		Auto(i,node)if(e[i].flow>0&&!vis[e[i].y])
			DFS(e[i].y);
	}
	void Solve(){
		up(dig,0,31){
			up(i,1,N){
				if(used[i])	tag[i]=((Val[i]&(1<<dig))>>dig);
				else 		tag[i]=-1;
			}
			Build();
			Dinic(dig);
			up(i,1,N)tag[i]=0;
			memset(vis,0,sizeof(vis));
			DFS(S);
			up(i,1,N)if(!used[i])Val[i]|=(tag[i]<<dig);
		}
		up(i,1,N)printf("%d\n",Val[i]);
	}
}
int main(){
	//freopen("input.in","r",stdin);
	using namespace solution;
	TT=read();
	while(TT--){
		Prepare();
		Solve();
	}
	return 0;
}
时间: 2024-10-31 15:35:35

SPOJ839 OPTM - Optimal Marks的相关文章

图论(网络流):SPOJ OPTM - Optimal Marks

OPTM - Optimal Marks You are given an undirected graph G(V, E). Each vertex has a mark which is an integer from the range [0..231 – 1]. Different vertexes may have the same mark. For an edge (u, v), we define Cost(u, v) = mark[u] xor mark[v]. Now we

SPOJ OPTM Optimal Marks

Optimal Marks Time Limit: 6000ms Memory Limit: 262144KB This problem will be judged on SPOJ. Original ID: OPTM64-bit integer IO format: %lld      Java class name: Main You are given an undirected graph G(V, E). Each vertex has a mark which is an inte

[SPOJ839]Optimal Marks

[SPOJ839]Optimal Marks 试题描述 You are given an undirected graph \(G(V, E)\). Each vertex has a mark which is an integer from the range \([0..2^{31} - 1]\). Different vertexes may have the same mark. For an edge \((u, v)\), we define \(Cost(u, v) = mark

SPOJ 839 Optimal Marks 最小割 经典 按位建图

胡伯涛论文中的一题,经典建模,由于二进制每一位异或不会相互影响,所以我们把问题转换模型,按位处理. 即已知一些点的标号0/1(还有些可以自己任意改),和一些边,边权定义为两端点标号的异或,要求边权和最小的标号方案. 我们联想到最小割求的是从源到汇容量最小的边权和. 建图: 标号为1的和源点相连,容量INF,标号为0的和汇点相连,容量INF,这些边是不能割掉的(这些点标号已经明确) 原图相连的边,连边,容量为1.(若将此边割掉,则两端点一个为0,一个为1,割为1) 跑完最大流后,在残量网络中dfs

SPOJ Optimal Marks(最小割的应用)

SPOJ Optimal Marks(最小割的应用) 真心好题,网络流简直无处不在,能够解决一些看似困难的问题,希望能从中学到其精髓--模型建立+建图 题意: 给定一个无向图,每个顶点都有对应值,每条边的权值为val[u] ^ val[u],同时已知其中某些点的值,求其他点的权值使得最终的图的边权和最小? 分析: 首先边与边之间异或操作,不太好直接处理,因为异或操作每一位运算相互独立,我们来逐位考虑,那么对于那些还未知的权值的点,这一位要么为0 ,要么为1,同时我们还得注意边的两个端点值相同则没

SP839 Optimal marks(最小割)

SP839 Optimal marks(最小割) 给你一个无向图G(V,E). 每个顶点都有一个int范围内的整数的标记. 不同的顶点可能有相同的标记.对于边(u,v),我们定义Cost(u,v)= mark [u] \(\oplus\) mark [v].现在我们知道某些节点的标记了.你需要确定其他节点的标记,以使边的总成本尽可能小.(0 < N <= 500, 0 <= M <= 3000) 先来看一下异或的性质,由于每一位是独立的,我们可以把每一位拉出来分开考虑,变成32个子

SPOJ839 Optimal Marks(最小割)

题目大概说给一张图,每个点都有权,边的权等于其两端点权的异或和,现已知几个点的权,为了使所有边的边权和最小,其他点的权值该是多少. 很有意思的一道题,完全看不出和网络流有什么关系. 考虑每个未知的点$x$的权的二进制的第$i$位$x_i$,其对边权和的贡献为$\sum_{(x,y)\in E}(2^i\cdot(x_i\ \hat{}\ y_i))=2^i\sum_{(x,y)\in E}(x_i\ \hat{}\ y_i)$,而$x_i$取值是$0$或$1$! 这样问题就明了了: 相当于对于每

BZOJ2400 Spoj 839 Optimal Marks

首先发现每一位二进制可以分开来做. 然后就变成0.1两种数了,考虑最小割. 设S表示选0,T表示选1,则 对于确定的点向数字对应的S/T连边,边权inf:然后原来图中有边的,互相连边,边权为1. 直接最小割即可,最后还要dfs一下来求出每个未确定的数选的是0还是1. 1 /************************************************************** 2 Problem: 2400 3 User: rausen 4 Language: C++ 5 R

BZOJ 2400 Optimal Marks 最小割

题目大意:给定一个无向图,一些点有权值,其它点的权值可以自己指定,要求指定这些点的权值,使每条边两边的点权异或值之和最小 在此基础上要求点权和最小 首先不考虑点权和最小这个条件 那么我们将每一位分开计算 我们会发现这是一个最小割的模型 令S集为0,T集为1,如果这个点的点权已经指定,则向相应集合连流量为INF的边 每条边的两端点之间连一条流量为1的边 跑最小割就是答案 现在我们将点权考虑进去 将原图每条边的流量扩大10000倍 如果一个点和S没有连边,就从S向这个点连一条流量为1的边 这样如果和