SP839 Optimal marks(最小割)

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

先来看一下异或的性质,由于每一位是独立的,我们可以把每一位拉出来分开考虑,变成32个子问题。

现在问题就变成了:一堆点是0,一堆点是1,一堆点没有标号,它们互相有一些边,一个边的权值只当一个点是0一个点是1时才是1,否则是0。求最小边权和

于是我们这样建图:(红色表示1,蓝色表示0,白色表示没有权值)

然后跑一个最小割即可。脑补一下,就是找出红色点势力和蓝色点势力的接触处的最小边数。

关于最小割建模的题,具体怎么操作,首先是定义割的含义,就是和s相连的点都定义成要选择的点,其它的点都不选择。关于边的值的定义,不能割的边设置成INF。这个算是套路。

由于题目要求点权和最小,因此我们应尽量让红色点最少。于是,跑完最大流以后,把从s能遍历到的点都标成1就可以满足红色点最少啦!(这个不会证,留坑。)

  1. #include <cstdio>
  2. #include <cstring>
  3. using namespace std;
  4. const int maxn=505, maxm=3005, INF=1e9;
  5. int T, n, m, k, src, dst;
  6. inline int min(int x, int y){ return x<y?x:y; }
  7. struct Edge{
  8. int to, nxt, f;
  9. }e[maxm*2+maxn], e1[maxm];
  10. int fir[maxn], cnte;
  11. void addedge(int x, int y, int v){
  12. Edge &ed=e[++cnte];
  13. ed.to=y; ed.nxt=fir[x]; ed.f=v; fir[x]=cnte; }
  14. void RESET(){ cnte=1; memset(fir, 0, sizeof(fir)); }
  15. int mark[maxn], gmark[maxn];
  16. int dep[maxn], q[maxn], head, tail;
  17. int bfs(){ //bfs来给图分层
  18. head=tail=0; memset(dep, 0, sizeof(dep));
  19. dep[src]=1; q[tail++]=src; int tmp;
  20. while (head<tail){
  21. tmp=q[head++];
  22. for (int i=fir[tmp]; i>0; i=e[i].nxt)
  23. if (e[i].f>0&&!dep[e[i].to]){
  24. dep[e[i].to]=dep[tmp]+1;
  25. q[tail++]=e[i].to;
  26. }
  27. }
  28. return dep[dst]?1:0;
  29. }
  30. int cur[maxn];
  31. int dfs(int u, int flow){ //flow表示从s流到当前点的最大流量 找出一条流
  32. if (u==dst) return flow;
  33. if (cur[u]==-1) return 0;
  34. for (int i=(cur[u]?cur[u]:fir[u]); i>0; i=e[i].nxt){
  35. cur[u]=i;
  36. if (dep[e[i].to]==dep[u]+1&&e[i].f){
  37. int minm=dfs(e[i].to, min(flow, e[i].f));
  38. if (minm>0){
  39. e[i].f-=minm; e[i^1].f+=minm;
  40. return minm;
  41. }
  42. }
  43. }
  44. cur[u]=-1;
  45. return 0;
  46. }
  47. void dinic(){
  48. while (bfs()){
  49. memset(cur, 0, sizeof(cur));
  50. while (dfs(src, INF));
  51. }
  52. }
  53. bool vis[maxn];
  54. void findzero(int u){
  55. vis[u]=true;
  56. for (int i=fir[u]; i; i=e[i].nxt){
  57. if (vis[e[i].to]||!e[i].f) continue;
  58. findzero(e[i].to);
  59. }
  60. }
  61. int uu[maxm], vv[maxm];
  62. int main(){
  63. scanf("%d", &T); int t;
  64. while (T--){
  65. scanf("%d%d", &n, &m); dst=n+1;
  66. for (int i=0; i<m; ++i)
  67. scanf("%d%d", &uu[i], &vv[i]);
  68. scanf("%d", &k);
  69. memset(mark, 0, sizeof(mark));
  70. memset(gmark, 0, sizeof(gmark));
  71. for (int i=1; i<=k; ++i){
  72. scanf("%d", &t); gmark[t]=1;
  73. scanf("%d", &mark[t]);
  74. }
  75. for (int i=0; i<31; ++i){
  76. RESET();
  77. for (int j=0; j<m; ++j)
  78. addedge(uu[j], vv[j], 1), addedge(vv[j], uu[j], 1);
  79. for (int j=1; j<=n; ++j){
  80. if (!gmark[j]) continue;
  81. if (mark[j]&(1<<i)) addedge(src, j, INF);
  82. else addedge(j, dst, INF);
  83. }
  84. dinic();
  85. memset(vis, 0, sizeof(vis)); findzero(src);
  86. for (int j=1; j<=n; ++j)
  87. if (vis[j]) mark[j]|=(1<<i);
  88. }
  89. for (int i=1; i<=n; ++i) printf("%d\n", mark[i]);
  90. }
  91. return 0;
  92. }

SP839 Optimal marks(最小割)的更多相关文章

  1. 【BZOJ2400】Spoj 839 Optimal Marks 最小割

    [BZOJ2400]Spoj 839 Optimal Marks Description 定义无向图中的一条边的值为:这条边连接的两个点的值的异或值. 定义一个无向图的值为:这个无向图所有边的值的和. ...

  2. 【BZOJ-2400】Spoj839Optimal Marks 最小割 + DFS

    2400: Spoj 839 Optimal Marks Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 567  Solved: 202[Submit ...

  3. [SP839]Optimal Marks

    luogu 题意 给你一个无向图\(G(V,E)\). 每个顶点都有一个int范围内的整数的标记. 不同的顶点可能有相同的标记. 对于边\((u,v)\),我们定义\(Cost(u,v)=\rm ma ...

  4. SPOJ839 Optimal Marks(最小割)

    题目大概说给一张图,每个点都有权,边的权等于其两端点权的异或和,现已知几个点的权,为了使所有边的边权和最小,其他点的权值该是多少. 很有意思的一道题,完全看不出和网络流有什么关系. 考虑每个未知的点$ ...

  5. spoj 839 Optimal Marks(二进制位,最小割)

    [题目链接] http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=17875 [题意] 给定一个图,图的权定义为边的两端点相抑或值的 ...

  6. SPOJ-OPTM Optimal Marks ★★(按位建图 && 最小割)

    [题意]给出一个无向图,每个点有一个标号mark[i],不同点可能有相同的标号.对于一条边(u, v),它的权值定义为mark[u] xor mark[v].现在一些点的标号已定,请决定剩下点的标号, ...

  7. SPOJ 839 OPTM - Optimal Marks (最小割)(权值扩大,灵活应用除和取模)

    http://www.spoj.com/problems/OPTM/ 题意: 给出一张图,点有点权,边有边权 定义一条边的权值为其连接两点的异或和 定义一张图的权值为所有边的权值之和 已知部分点的点权 ...

  8. SPOJ 839 Optimal Marks(最小割的应用)

    https://vjudge.net/problem/SPOJ-OPTM 题意: 给出一个无向图G,每个点 v 以一个有界非负整数 lv 作为标号,每条边e=(u,v)的权w定义为该边的两个端点的标号 ...

  9. Optimal Marks SPOJ - OPTM (按位枚举-最小割)

    题意:给一张无向图,每个点有其点权,边(i,j)的cost是\(val_i\ XOR \ val_j\).现在只给出K个点的权值,求如何安排其余的点,使总花费最小. 分析:题目保证权值不超过32位整型 ...

随机推荐

  1. VS编译linux项目生成静态库并在另一个项目中静态链接的方法

    VS2017也推出很久了,在单位的时候写linux的服务端程序只能用vim,这让用惯了IDE的我很难受. 加上想自己撸一套linux上的轮子,决定用VS开工远程编写调试linux程序. 在window ...

  2. c# webapi2 实用详解

    本文介绍webapi的使用知识 发布webapi的问题 配置问题 webapi的项目要前端访问,需要在web.config配置文件中添加如下配置 在system.webServer节点下面添加 < ...

  3. Profile配置

    Profile是Spring用来针对不同环境对不同的配置提供支持的,全局Profile配置使用application-{profile}.properties application.properti ...

  4. Tomcat 不能正常启动

    启动过程提示: Stopping ProtocolHandler ["http-bio-8080"] the JRE_HOME environment variable is no ...

  5. DAY15-HTTP协议简述

    HTTP协议 一.HTTP协议简介 超文本传输协议(英文:HyperText Transfer Protocol,缩写:HTTP)是一种用于分布式.协作式和超媒体信息系统的应用层协议.HTTP是万维网 ...

  6. DAY13-前端之JavaScript

    JavaScript概述 JavaScript的历史 1992年Nombas开发出C-minus-minus(C--)的嵌入式脚本语言(最初绑定在CEnvi软件中),后将其改名ScriptEase(客 ...

  7. php中COM函数的使用

    php里的com类可以操作window系统上的东西 例如:可以在本地打开一个word文档,然后写入东西,只用于window系统 需要加载php_com_dotnet.dll模块   $word = n ...

  8. sql编写注意

    DROP TABLE IF EXISTS `imooc_pro`; CREATE TABLE `imooc_pro`( `id` int unsigned auto_increment key, `p ...

  9. Centos彻底完全删除已安装软件的办法

    1.查询是否安装了软件 rpm -qa | grep -i 软件名 rpm -qa | grep php 2.删除已安装的软件包 根据第一步显示的软件包名,一个个删除 sudo rpm -e -- 包 ...

  10. C++实现矩阵的相加/相称/转置/求鞍点

    1.矩阵相加 两个同型矩阵做加法,就是对应的元素相加. #include<iostream> using namespace std; int main(){ int a[3][3]={{ ...