https://vjudge.net/problem/SPOJ-OPTM
题意:
给出一个无向图G,每个点 v 以一个有界非负整数 lv 作为标号,每条边e=(u,v)的权w定义为该边的两个端点的标号的异或值,即W=lu XOR lv。现已知其中部分点的标号,求使得该图的总边权和最小的标号赋值。即最小化:
思路:
这道题目在刘伯涛的论文里讲得十分的详细,看看论文就可以啦。
XOR运算是根据二进制的每一位来计算的,,并且因为每一位都是相互独立的,互不影响,所以可以转化为下式:
接下来对于每一位都新建图,对于已经标号的顶点来说,如果该位是1,则与源点相连,否则与汇点相连,容量均为INF。如果本来就相连的点还是需要相连的,容量为1。对于每个还没有标号的点来说,在这一位的取值要么是1,要么是0,这就很符合最小割。在跑完最大流之后,只需要从源点出发,凡是能到达的点都是取值为1的。
1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<cstdio> 5 #include<vector> 6 #include<stack> 7 #include<queue> 8 #include<cmath> 9 #include<map> 10 #include<set> 11 using namespace std; 12 typedef long long ll; 13 typedef pair<int,int> pll; 14 const int INF = 0x3f3f3f3f; 15 const int maxn = 5000 + 5; 16 17 int n, m, k; 18 int val[maxn]; 19 int ans[maxn]; 20 int vis[maxn]; 21 int mp[maxn][maxn]; 22 23 struct Edge 24 { 25 int from,to,cap,flow; 26 Edge(int u,int v,int w,int f):from(u),to(v),cap(w),flow(f){} 27 }; 28 29 struct Dinic 30 { 31 int n,m,s,t; 32 vector<Edge> edges; 33 vector<int> G[maxn]; 34 bool vis[maxn]; 35 int cur[maxn]; 36 int d[maxn]; 37 38 void init(int n) 39 { 40 this->n=n; 41 for(int i=0;i<n;++i) G[i].clear(); 42 edges.clear(); 43 } 44 45 void AddEdge(int from,int to,int cap) 46 { 47 edges.push_back( Edge(from,to,cap,0) ); 48 edges.push_back( Edge(to,from,0,0) ); 49 m=edges.size(); 50 G[from].push_back(m-2); 51 G[to].push_back(m-1); 52 } 53 54 bool BFS() 55 { 56 queue<int> Q; 57 memset(vis,0,sizeof(vis)); 58 vis[s]=true; 59 d[s]=0; 60 Q.push(s); 61 while(!Q.empty()) 62 { 63 int x=Q.front(); Q.pop(); 64 for(int i=0;i<G[x].size();++i) 65 { 66 Edge& e=edges[G[x][i]]; 67 if(!vis[e.to] && e.cap>e.flow) 68 { 69 vis[e.to]=true; 70 d[e.to]=d[x]+1; 71 Q.push(e.to); 72 } 73 } 74 } 75 return vis[t]; 76 } 77 78 int DFS(int x,int a) 79 { 80 if(x==t || a==0) return a; 81 int flow=0, f; 82 for(int &i=cur[x];i<G[x].size();++i) 83 { 84 Edge &e=edges[G[x][i]]; 85 if(d[e.to]==d[x]+1 && (f=DFS(e.to,min(a,e.cap-e.flow) ) )>0) 86 { 87 e.flow +=f; 88 edges[G[x][i]^1].flow -=f; 89 flow +=f; 90 a -=f; 91 if(a==0) break; 92 } 93 } 94 return flow; 95 } 96 97 int Maxflow(int s,int t) 98 { 99 this->s=s; this->t=t; 100 int flow=0; 101 while(BFS()) 102 { 103 memset(cur,0,sizeof(cur)); 104 flow +=DFS(s,INF); 105 } 106 return flow; 107 } 108 }DC; 109 110 void dfs(int u, int x) 111 { 112 vis[u]=1; 113 ans[u]+=x; 114 for(int i=0;i<DC.G[u].size();i++) 115 { 116 Edge& e=DC.edges[DC.G[u][i]]; 117 if(!vis[e.to] && e.cap>e.flow) 118 dfs(e.to,x); 119 } 120 } 121 122 void solve() 123 { 124 int src=0,dst=n+1; 125 int bite=1; 126 while(true) 127 { 128 DC.init(dst+1); 129 for(int i=1;i<=n;i++) 130 for(int j=1;j<=n;j++) 131 if(mp[i][j]) DC.AddEdge(i,j,1); 132 133 bool flag=false; 134 for(int i=1;i<=n;i++) 135 { 136 if(val[i]!=-1) 137 { 138 if(val[i]>=1) 139 { 140 flag=true; 141 } 142 if(val[i]&1) 143 { 144 DC.AddEdge(src,i,INF); 145 } 146 else 147 { 148 DC.AddEdge(i,dst,INF); 149 } 150 val[i]>>=1; 151 } 152 } 153 154 if(!flag) break; 155 DC.Maxflow(src,dst); 156 memset(vis,0,sizeof(vis)); 157 dfs(src,bite); 158 bite<<=1; 159 } 160 } 161 162 int main() 163 { 164 //freopen("in.txt","r",stdin); 165 int T; 166 scanf("%d",&T); 167 while(T--) 168 { 169 memset(mp,0,sizeof(mp)); 170 scanf("%d%d",&n,&m); 171 for(int i=0;i<m;i++) 172 { 173 int u,v; 174 scanf("%d%d",&u,&v); 175 mp[u][v]=mp[v][u]=1; 176 } 177 memset(val,-1,sizeof(val)); 178 scanf("%d",&k); 179 for(int i=0;i<k;i++) 180 { 181 int u,v; 182 scanf("%d%d",&u,&v); 183 val[u]=v; 184 } 185 memset(ans,0,sizeof(ans)); 186 solve(); 187 for(int i=1;i<=n;i++) 188 { 189 printf("%d ",ans[i]); 190 } 191 } 192 return 0; 193 }