最大流最小割定理的应用
添加源点(src)与汇点(sink)
由于P是偶数,那么对于点i与j,若gcd(x[i] ^ y[i] ^ x[j] ^ y[j],p) > 1,则可共存,可将点集分为两个集合a,b(二分图),a中点的x与y坐标同奇同偶,y中点的坐标一奇一偶,src与a中点连x[i] & y[i]的边,b中点与sink连x[i]&y[i]的边。若两点不能共存(该两点一定一个在a一个在b),连INF=max的边。求出最小割,ans=sum-maxflow().
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 #include<vector> 6 #include<stack> 7 #include<queue> 8 #include<map> 9 #include<cstdlib> 10 #include<cmath> 11 using namespace std; 12 const int MAXM = 2000011; 13 const int MAXN = 511; 14 long long INF = 0; 15 struct edge 16 { 17 int v,nxt; 18 long long f; 19 }; 20 edge e[MAXM]; 21 int g[MAXN]; 22 int nume,n,p; 23 int x[MAXN],y[MAXN],dist[MAXN]; 24 bool vis[MAXN]; 25 int src,sink; 26 int a[MAXN],b[MAXN]; 27 int tot1,tot2; 28 void init() 29 { 30 memset(g,0,sizeof(g)); 31 nume = 1; 32 for (int i = 1; i <= n; i++) scanf("%d%d",&x[i],&y[i]); 33 } 34 void addedge(int u,int v,long long c) 35 { 36 e[++nume].v = v; 37 e[nume].f = c; 38 e[nume].nxt = g[u]; 39 g[u] = nume; 40 e[++nume].v = u; 41 e[nume].f = 0; 42 e[nume].nxt = g[v]; 43 g[v] = nume; 44 } 45 int gcd(int a,int b) 46 { 47 if (b == 0) return a; 48 return gcd(b,a%b); 49 } 50 queue<int>que; 51 void bfs() 52 { 53 memset(dist,0,sizeof(dist)); 54 while (!que.empty()) que.pop(); 55 vis[src] = 1; 56 que.push(src); 57 while (!que.empty()) 58 { 59 int u = que.front(); 60 que.pop(); 61 for (int i = g[u];i;i = e[i].nxt) 62 if (e[i].f && !vis[e[i].v]) 63 { 64 que.push(e[i].v); 65 dist[e[i].v] = dist[u] + 1; 66 vis[e[i].v] = 1; 67 } 68 } 69 } 70 /*inline long long mint(int x,long long y) 71 { 72 if (x < y) return x; 73 return y; 74 }*/ 75 long long dfs(int u,long long delta) 76 { 77 if (u == sink) 78 { 79 return delta; 80 } 81 else 82 { 83 long long ret = 0; 84 for (int i = g[u]; delta && i; i = e[i].nxt) 85 if (e[i].f && dist[e[i].v] == dist[u] +1) 86 { 87 long long dd = dfs(e[i].v,min(e[i].f,delta)); 88 e[i].f -= dd; 89 e[i ^ 1].f += dd; 90 delta -= dd; 91 ret += dd; 92 } 93 return ret; 94 } 95 } 96 long long maxflow() 97 { 98 long long ret = 0; 99 while (1) 100 { 101 memset(vis,0,sizeof(vis)); 102 bfs(); 103 if (!vis[sink]) return ret; 104 ret += dfs(src,INF); 105 } 106 } 107 int main() 108 { 109 while (scanf("%d%d",&n,&p) != EOF) 110 { 111 init(); 112 src = 0; sink = n + 1; 113 tot1 = tot2 = 0; 114 memset(a,0,sizeof(a)); 115 memset(b,0,sizeof(b)); 116 for (int i = 1; i <= n; i++) 117 { 118 int s1 = x[i] % 2,s2 = y[i] % 2; 119 int s = s1 + s2; 120 if (s % 2 == 0) a[++tot1] = i; else b[++tot2] = i; 121 } 122 long long ans = 0ll; 123 for (int i = 1;i <= n; i++) ans += (x[i] & y[i]); 124 INF = ans; 125 for (int i = 1; i <= tot1; i++) addedge(0,a[i],x[a[i]] & y[a[i]]); 126 for (int i = 1; i <= tot2; i++) addedge(b[i],n + 1,x[b[i]] & y[b[i]]); 127 for (int i = 1; i <= tot1; i++) 128 for (int j = 1; j <= tot2; j++) 129 if (gcd(x[a[i]] ^ y[a[i]] ^ x[b[j]] ^ y[b[j]],p) == 1) addedge(a[i],b[j],INF); 130 ans = ans - maxflow(); 131 cout<<ans<<endl; 132 } 133 return 0; 134 }