【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\n",now); 64 } 65 //printf("%d\n",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 }