题意:给出一个无向图, 图中的一些点有mark值, 每条边<u,v>的权值为mark[u]^mark[v], 现在给出了一些点的mark值,现在想让你求出其他点的mark值让边权和最小。 点的个数100, 边的的个数为3000
思路: 对于mark值不同位的值是不影响的,所以可以一位一位的处理。对于每一位只能是1和0,对不不知道的点的mark只能是1和0,所以最后的问题就是将这些点分到两个集合中。 两个点之间如果不是一个集合并且还有边的话那么答案就要花费1. 我们这样建图。
对于当前位mark值为1的点建一个<s,u, INF>的边, 对于为0的点我们建立<u,t,INF>的边。 对于普通的边建立一个
<u,v,1>,<v,u,1>的边。 让割最小就行。这样就转化成了最大刘德问题。
AC代码:

1 #include <cstdio> 2 #include <cstring> 3 #include <queue> 4 #include <string> 5 #include <iostream> 6 using namespace std; 7 const int N = 600, M = 30010, INF=1<<29; 8 struct EDGE 9 { 10 int u, v, cap, next; 11 }edge[M], p[M]; 12 13 int num, head[N], mark[N], ans[N]; 14 int gap[N], dis[N], pre[N], cur[N]; 15 int n, m; 16 bool used[N]; 17 18 void init() 19 { 20 int u, w, k; 21 scanf("%d%d", &n, &m); 22 for(int i=0; i<m; i++) 23 { 24 scanf("%d%d", &p[i].u, &p[i].v); 25 } 26 memset(mark, -1, sizeof(mark)); 27 memset(ans, 0, sizeof(ans)); 28 scanf("%d", &k); 29 while(k--) 30 { 31 scanf("%d%d", &u, &w); 32 mark[u] = w; 33 } 34 } 35 36 void add(int u, int v, int w) 37 { 38 edge[num].u = u; 39 edge[num].v = v; 40 edge[num].cap = w; 41 edge[num].next = head[u]; 42 head[u] = num++; 43 } 44 45 void build(int k) 46 { 47 for(int i=1; i<=n; i++) 48 { 49 if(mark[i] != -1) 50 { 51 if(mark[i]&(1<<k)) 52 { 53 add(0, i, INF); 54 add(i, 0, 0); 55 } 56 else 57 { 58 add(i, n+1, INF); 59 add(n+1, i, 0); 60 } 61 } 62 } 63 for(int i=0; i<m; i++) 64 { 65 add(p[i].u, p[i].v, 1); 66 add(p[i].v, p[i].u, 0); 67 add(p[i].v, p[i].u, 1); 68 add(p[i].u, p[i].v, 0); 69 } 70 } 71 72 int SAP(int s,int t) //sap模版 73 { 74 memset(gap,0,sizeof(gap)); 75 memset(dis,0,sizeof(dis)); 76 int i; 77 for(i=0; i<=t;i++) 78 { 79 cur[i] = head[i]; 80 } 81 int top=s; 82 gap[s]=t+1; 83 long long maxflow=0,flow=M; 84 while(dis[s] < t+1) 85 { 86 for(i=cur[top];i != -1;i = edge[i].next) 87 { 88 if(edge[i].cap > 0 && dis[top] == dis[edge[i].v] + 1) 89 break; 90 } 91 if(i != -1) 92 { 93 cur[top] = i; 94 int v = edge[i].v; 95 if(edge[i].cap < flow) 96 { 97 flow = edge[i].cap; 98 } 99 top = v; 100 pre[v] = i; 101 if(top == t) 102 { 103 maxflow += flow; 104 while(top != s) 105 { 106 edge[pre[top]].cap -= flow; 107 edge[pre[top]^1].cap += flow; 108 top = edge[pre[top]^1].v; 109 } 110 flow = M; 111 } 112 } 113 else 114 { 115 if(--gap[dis[top]] == 0) 116 { 117 break; 118 } 119 dis[top] = t+1; 120 cur[top] = head[top]; 121 for(int j=head[top];j != -1;j=edge[j].next) 122 { 123 if(edge[j].cap > 0 && dis[edge[j].v] + 1 < dis[top]) 124 { 125 dis[top] = dis[edge[j].v] + 1; 126 cur[top] = j; 127 } 128 } 129 gap[dis[top]]++; 130 if(top != s) 131 { 132 top = edge[pre[top]^1].v; 133 } 134 } 135 } 136 return maxflow; 137 } 138 139 void dfs(int u, int k) 140 { 141 int v; 142 if(u>=1 && u<=n) 143 { 144 ans[u] |= (1<<k); 145 } 146 used[u] = 1; 147 for(int i=head[u]; i!=-1; i=edge[i].next) 148 { 149 if(edge[i].cap>0 && !used[edge[i].v]) 150 { 151 dfs(edge[i].v, k); 152 } 153 } 154 } 155 156 void solve() 157 { 158 for(int i=0; i<32; i++) 159 { 160 num = 0; 161 memset(head, -1, sizeof(head)); 162 163 build(i); 164 SAP(0,n+1); 165 memset(used, 0, sizeof(used)); 166 dfs(0,i); 167 } 168 for(int i=1; i<=n; i++) 169 { 170 printf("%d\n", ans[i]); 171 } 172 } 173 174 int main() 175 { 176 int t; 177 scanf("%d", &t); 178 while(t--) 179 { 180 init(); 181 solve(); 182 } 183 return 0; 184 }
来源:https://www.cnblogs.com/gufeiyang/archive/2012/10/08/2715257.html