【SPOJ839】最优标号

【题目描述】

给你一张无向图G(V,E)。每个顶点都有一个标号,它是一个[0,2^31-1]内的整数。不同的顶点可能会有相同的标号。

对每条边(u,v),我们定义其费用cost(u,v)为u的标号与v的标号的异或值。

现在我们知道一些顶点的标号。你需要确定余下顶点的标号使得所有边的费用和尽可能小。

【输入格式】

输入文件的第一行有两个整数N,M(1<=N<=500,0<=M<=3000),N是图的点数,M是图的边数。

接下来有M行,每行有两个整数u,v,代表一条连接u,v的边。

接下来有一个整数K,代表已知标号的顶点个数。接下来的K行每行有两个整数u,p,代表点u的标号是p。假定这些u不会重复。

【输出格式】

输出一行一个整数,即最小的费用和。

【分析】

由题目叙述中,我们可以很容易看到,对于每个顶点的标号数的每个二进制位上来说,它与前后该数的其他二进制位是完全没有任何联系的,所以我们不妨把每个数的二进制位拆开来组图,然后再求每个图的最小割就可以了。

在建图的时候,要注意的是,需要把二进制位上为1的和二进制位上为0的分开连接到源点和汇点。

最后,注意重边!

  1 #include <cstdlib>
  2 #include <iostream>
  3 #include <cstring>
  4 #include <cmath>
  5 #include <cstdio>
  6 #include <queue>
  7 const int maxn=510;
  8 const int maxm=3010;
  9 const int INF=10000*10000;
 10 using namespace std;
 11 struct liu
 12 {
 13        int c,f;
 14        liu(){c=0;f=0;}
 15 }maps[maxn][maxn];
 16 int shu[maxn],map[maxn][maxn];
 17 int bh[maxn],path[maxn],dist[maxn];
 18 
 19 int n,m,k;
 20 long long solve(int times);
 21 void make_maps(int times);
 22 bool BFS();
 23 int dfs(int u,int low);
 24 
 25 int main()
 26 {
 27     int i;
 28     memset(shu,-1,sizeof(shu));
 29     memset(map,0,sizeof(map));
 30     //读入数据 
 31     scanf("%d%d",&n,&m);
 32     for (i=1;i<=m;i++) 
 33     {
 34         int u,v;
 35         scanf("%d%d",&u,&v);
 36         map[u][v]++;
 37         map[v][u]++;
 38     }
 39     scanf("%d",&k);
 40     for (i=1;i<=k;i++) 
 41     {
 42         int u,p;
 43         scanf("%d%d",&u,&p);
 44         shu[u]=p;
 45     }
 46     
 47     long long ans=0;
 48     //注意求解次数 
 49     for (i=0;i<=31;i++) ans+=solve(i);//求解最大流 
 50     printf("%lld",ans);
 51     return 0;
 52 }
 53 //求解函数 
 54 long long solve(int times)
 55 {
 56      int i,flow=0,pos;
 57      
 58      make_maps(times);
 59      while ( BFS() )
 60      {
 61            int now;
 62            while (now=dfs(0,INF)) flow+=now;
 63            //printf("%d
",now);
 64      }
 65      //printf("%d
",flow);
 66      return (long long)flow<<times;
 67 }
 68 //构图 
 69 void make_maps(int times)
 70 {
 71      int i,j,bh[maxn];
 72      //-1代表还没有开始标号 
 73      memset(bh,-1,sizeof(bh));
 74      memset(maps,0,sizeof(maps));
 75      for (i=1;i<=n;i++) 
 76      {
 77          if (shu[i]==-1) continue;
 78          bh[i]=((1<<times)&shu[i])==(1<<times);//二进制位
 79          //超级源汇
 80          if (bh[i]!=0) {maps[0][i].f=0;maps[0][i].c=INF;}
 81          else {maps[i][n+1].f=0;maps[i][n+1].c=INF;}
 82      }
 83      for (i=1;i<=n;i++)
 84      for (j=1;j<=n;j++)
 85      {
 86          if (map[i][j]==0) continue;//保留原边 
 87          maps[i][j].c=map[i][j];
 88          maps[i][j].f=0;
 89      }
 90      return;
 91 }
 92 bool BFS()//BFS构建层次网络 
 93 {
 94      int i,u;
 95      queue<int>Q;
 96      memset(dist,-1,sizeof(dist));
 97      dist[0]=0;
 98      Q.push(0);
 99      while (!Q.empty())
100      {
101            int u=Q.front();Q.pop();
102            for (i=0;i<=n+1;i++)
103            {
104                int v=i;
105                if (dist[v]==-1 && maps[u][v].c-maps[u][v].f>0)
106                {
107                    Q.push(v);
108                    dist[v]=dist[u]+1;
109                }
110            }
111      } 
112      return (dist[n+1]!=-1);
113 }
114 int dfs(int v,int low)//增广 
115 {
116     int i;
117     if (v==(n+1) || low==0) return low;
118     int flow=0,f;
119     for (i=0;i<=(n+1);i++)
120     {
121         if (maps[v][i].c-maps[v][i].f>0 && dist[i]==dist[v]+1)
122         {
123             if (f=dfs(i,min(low,maps[v][i].c-maps[v][i].f)))
124             {
125                 maps[v][i].f+=f;
126                 maps[i][v].f-=f;
127                 flow+=f;
128                 low-=f;
129                 if (low==0) break;
130             }
131         } 
132     }
133     return flow;
134 }
View Code
原文地址:https://www.cnblogs.com/hoskey/p/3721837.html