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$!
这样问题就明了了:
- 相当于对于每个点中的每一位让它们取0或1
- 对于未知的取0或1花费都为0
- 对于已知的是0或1,那么对应取0或1的花费也是0,而取1或0的花费是INF
- 对于边其两端点如果取值不同则需要额外$2^i$的花费
这样这就是一个经典的二者选其一花费最小的最小割模型了!
另外不需要每个点都拆成最多二进制位数个数的点,这样容量网络的点上万个——因为各个位是独立的,所以可以分开求,即跑二进制位数个数次的网络流。
最后求答案,只需从源点floodfill找到S集合有哪几个点就知道所有点的各个位的取值了。
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
#define INF (1<<30)
#define MAXN 555
#define MAXM 555*555*2 struct Edge{
int v,cap,flow,next;
}edge[MAXM];
int vs,vt,NE,NV;
int head[MAXN]; void addEdge(int u,int v,int cap){
edge[NE].v=v; edge[NE].cap=cap; edge[NE].flow=;
edge[NE].next=head[u]; head[u]=NE++;
edge[NE].v=u; edge[NE].cap=; edge[NE].flow=;
edge[NE].next=head[v]; head[v]=NE++;
} int level[MAXN];
int gap[MAXN];
void bfs(){
memset(level,-,sizeof(level));
memset(gap,,sizeof(gap));
level[vt]=;
gap[level[vt]]++;
queue<int> que;
que.push(vt);
while(!que.empty()){
int u=que.front(); que.pop();
for(int i=head[u]; i!=-; i=edge[i].next){
int v=edge[i].v;
if(level[v]!=-) continue;
level[v]=level[u]+;
gap[level[v]]++;
que.push(v);
}
}
} int pre[MAXN];
int cur[MAXN];
int ISAP(){
bfs();
memset(pre,-,sizeof(pre));
memcpy(cur,head,sizeof(head));
int u=pre[vs]=vs,flow=,aug=INF;
gap[]=NV;
while(level[vs]<NV){
bool flag=false;
for(int &i=cur[u]; i!=-; i=edge[i].next){
int v=edge[i].v;
if(edge[i].cap!=edge[i].flow && level[u]==level[v]+){
flag=true;
pre[v]=u;
u=v;
//aug=(aug==-1?edge[i].cap:min(aug,edge[i].cap));
aug=min(aug,edge[i].cap-edge[i].flow);
if(v==vt){
flow+=aug;
for(u=pre[v]; v!=vs; v=u,u=pre[u]){
edge[cur[u]].flow+=aug;
edge[cur[u]^].flow-=aug;
}
//aug=-1;
aug=INF;
}
break;
}
}
if(flag) continue;
int minlevel=NV;
for(int i=head[u]; i!=-; i=edge[i].next){
int v=edge[i].v;
if(edge[i].cap!=edge[i].flow && level[v]<minlevel){
minlevel=level[v];
cur[u]=i;
}
}
if(--gap[level[u]]==) break;
level[u]=minlevel+;
gap[level[u]]++;
u=pre[u];
}
return flow;
}
int x[],y[],u[],p[];
int ans[];
bool vis[];
void dfs(int u){
vis[u]=;
for(int i=head[u]; i!=-; i=edge[i].next){
int v=edge[i].v;
if(vis[v] || edge[i].cap==edge[i].flow) continue;
dfs(v);
}
}
int main(){
int t,n,m,a,b,k;
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
for(int i=; i<m; ++i){
scanf("%d%d",x+i,y+i);
}
scanf("%d",&k);
for(int i=; i<k; ++i){
scanf("%d%d",u+i,p+i);
}
memset(ans,,sizeof(ans));
for(int i=; i<; ++i){
vs=; vt=n+; NV=vt+; NE=;
memset(head,-,sizeof(head));
for(int j=; j<m; ++j){
addEdge(x[j],y[j],);
addEdge(y[j],x[j],);
}
for(int j=; j<k; ++j){
if((p[j]>>i)&) addEdge(vs,u[j],INF);
else addEdge(u[j],vt,INF);
}
ISAP();
memset(vis,,sizeof(vis));
dfs(vs);
for(int j=; j<=n; ++j){
if(vis[j]) ans[j]+=(<<i);
}
}
for(int i=; i<=n; ++i){
printf("%d\n",ans[i]);
}
}
return ;
}
SPOJ839 Optimal Marks(最小割)的更多相关文章
- 【BZOJ2400】Spoj 839 Optimal Marks 最小割
[BZOJ2400]Spoj 839 Optimal Marks Description 定义无向图中的一条边的值为:这条边连接的两个点的值的异或值. 定义一个无向图的值为:这个无向图所有边的值的和. ...
- [SPOJ839]Optimal Marks
[SPOJ839]Optimal Marks 试题描述 You are given an undirected graph \(G(V, E)\). Each vertex has a mark wh ...
- spoj839 Optimal Marks(最小割,dinic)
题目大意: 给你一个无向图\(G(V,E)\). 每个顶点都有一个int范围内的整数的标记. 不同的顶点可能有相同的标记. 对于边\((u,v)\),我们定义\(Cost(u,v)=mark [u]\ ...
- 【BZOJ-2400】Spoj839Optimal Marks 最小割 + DFS
2400: Spoj 839 Optimal Marks Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 567 Solved: 202[Submit ...
- SP839 Optimal marks(最小割)
SP839 Optimal marks(最小割) 给你一个无向图G(V,E). 每个顶点都有一个int范围内的整数的标记. 不同的顶点可能有相同的标记.对于边(u,v),我们定义Cost(u,v)= ...
- spoj 839 Optimal Marks(二进制位,最小割)
[题目链接] http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=17875 [题意] 给定一个图,图的权定义为边的两端点相抑或值的 ...
- SPOJ-OPTM Optimal Marks ★★(按位建图 && 最小割)
[题意]给出一个无向图,每个点有一个标号mark[i],不同点可能有相同的标号.对于一条边(u, v),它的权值定义为mark[u] xor mark[v].现在一些点的标号已定,请决定剩下点的标号, ...
- SPOJ 839 OPTM - Optimal Marks (最小割)(权值扩大,灵活应用除和取模)
http://www.spoj.com/problems/OPTM/ 题意: 给出一张图,点有点权,边有边权 定义一条边的权值为其连接两点的异或和 定义一张图的权值为所有边的权值之和 已知部分点的点权 ...
- SPOJ 839 Optimal Marks(最小割的应用)
https://vjudge.net/problem/SPOJ-OPTM 题意: 给出一个无向图G,每个点 v 以一个有界非负整数 lv 作为标号,每条边e=(u,v)的权w定义为该边的两个端点的标号 ...
随机推荐
- php substr中文乱码最有效到解决办法 转:http://blog.sina.com.cn/s/blog_49b531af0100esah.html
(2009-07-29 12:29:38) 转载▼ 标签: php substr文乱码 网站开发 it 直接使用PHP函数substr截取中文字符可能会出现乱码,主要是substr可能硬生生的将一 ...
- ubuntu12 apache2部署多个网站的方法
由于对apache2的配置不是很精通.吃了不少瘪. 这里总结下,希望对碰到同样问题的人带来帮助: 假设需求是有两个站点,site1和site2.其端口分别为80和8080. 1. 配置监听端口 修改 ...
- 找不到提交和更新按钮,subversion不见了,无法更新和上传代码
1.查看settings/plugins/下有没有subversion 插件,如果有,确保勾上. 2.VCS->Enable Version Control Integration...
- Linux 系统安全 抵御TCP的洪水
抵御TCP的洪水 分类: LINUX tcp_syn_retries :INTEGER默认值是5对 于一个新建连接,内核要发送多少个 SYN 连接请求才决定放弃.不应该大于255,默认值是5,对应于1 ...
- 【转】kettle 的内存设置及输出日志的时间类型
本文转载自:http://blog.csdn.net/dqswuyundong/archive/2010/10/19/5952004.aspx 设置kettle的内存 REM ************ ...
- iOS 中的第三方库管理工具
xcode没有android studio中的gradle进行第三方库管理,但是有第三方的库管理工具CocoaPods,https://github.com/CocoaPods/CocoaPods/w ...
- Windows下尝试PHP7提示丢失VCRUNTIME140.DLL的问题解决
前天PHP7.0.0正式版发布了,有一些比较好的改进,官方也说速度比php5.6快了两倍,性能上有了很大提升,并且也发布了从php5.x向php7迁移的问题,所以今后php网站迁移后能够大幅度的提升网 ...
- Java for LeetCode 146 LRU Cache 【HARD】
Design and implement a data structure for Least Recently Used (LRU) cache. It should support the fol ...
- VirtualBox 虚拟 Ubuntu 的一些感想
之前有说过最近在学习Shell,公司及家里的电脑目前都是Windows系统,进行shell学习主要是用一些模拟linux环境的软件,比如banbun.cygwin banbun的功能很强大,集成了oh ...
- Docker跨主机通信之路由
一.实验环境: 主机名 主机IP Docker0_IP Docker1 192.168.88.130 172.17.0.1 Docker2 192.168.88.131 172.18.0.1 二.实验 ...