这道题目是《最小割模型在信息学竞赛中的应用》中的例题
①异或拆成一位一位的这个之前做过题
②学习了:”在给定的图中求完最大流后,如何求出S-T割中,两个点集分别有哪些点"
直接在跑过最大流后的图上,用cap != 0 的边做搜索就可以了
一个最大流可能对应好几个割, 要求出不同的割可以通过不同的建图方式来实现
③个人看法:
在做这个题目之前呢
最小割模型感觉上比最大流模型抽象很多,最大流模型很容易想出一个具体的“半现实”的问题
最小割模型就很迷,除了题目指明要求最小割的大小,一下子想不到什么对应的现实问题
论文作者在分析这个题目的时候顺带一定程度上的解决了我这个问题
“点分两类;异类间的关系计入目标函数;优化目标是最小化”
这样的问题就可以用最小割模型解决
以后遇到一定要想到啊
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <algorithm>
#include <stack>
#include <cctype>
#include <cmath>
#include <vector>
#include <sstream>
#include <bitset>
#include <deque>
#include <iomanip>
using namespace std;
#define pr(x) cout << "x = " << x << endl;
#define bug cout << "bugbug" << endl;
typedef long long ll;
typedef pair<int, int> P;
typedef unsigned int uint;
const int MOD = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int maxn = 5e2 + 4;
const int maxm = 3e3 + 4;
struct Edge{
int to, cab, rev;
Edge(int _to, int _cap, int _rev):to(_to), cab(_cap), rev(_rev){
}
};
vector<Edge> G[maxn];
int level[maxn], iter[maxn], n, m, u[maxm], v[maxm], cab, K, maxv;
ll num[maxn], pos[maxn], val[maxn];
bool tag[maxn];
inline void add(int u, int v, int cap){
G[u].push_back(Edge(v, cap, G[v].size()));
G[v].push_back(Edge(u, 0, G[u].size() - 1));
return;
}
void bfs(int s, int t){
level[s] = 0;
queue<int> q;
q.push(s);
while(q.size()){
int u = q.front(); q.pop();
for (int i = 0; i < G[u].size(); ++i){
int to = G[u][i].to;
if (level[to] == -1 && G[u][i].cab > 0){
level[to] = level[u] + 1;
q.push(to);
}
}
}
return;
}
int dfs(int u, int t, int f){
if (u == t) return f;
for (int& i = iter[u]; i < G[u].size(); ++i){
int to = G[u][i].to;
if (level[to] > level[u] && G[u][i].cab > 0){
int d = dfs(to, t, min(f, G[u][i].cab));
if (d > 0){
G[u][i].cab -= d;
G[to][G[u][i].rev].cab += d;
return d;
}
}
}
return 0;
}
int max_flow(int s, int t){
int ret = 0, tmp;
while(true){
memset(level, -1, sizeof level);
bfs(s, t);
if (level[t] == -1) return ret;
memset(iter, 0, sizeof iter);
while((tmp = dfs(s, t, inf)) != 0) ret += tmp;
}
}
bool vis[maxn];
void DFS(int u, ll j){
vis[u] = true;
for (int i = 0; i < G[u].size(); ++i){
int to = G[u][i].to;
if (vis[to] || G[u][i].cab == 0) continue;
num[to] |= 1 << j;
DFS(to, j);
}
return;
}
void Solve(){
int i, j, k;
for (i = 0; i <= maxv; ++i){
for (j = 0; j <= n + 1 + 1; ++j) G[j].clear();
for (j = 1; j <= K; ++j){
if (val[j] >> i & 1) add(0, pos[j], inf);
else add(pos[j], n+1, inf);
}
for (j = 1; j <= m; ++j){
add(u[j], v[j], 1);
add(v[j], u[j], 1);
}
max_flow(0, n+1);
memset(vis, false, sizeof vis);
DFS(0, i);
}
return;
}
int main(){
//必须编译过才能交
// ios::sync_with_stdio(false);
int ik, i, j, k, kase;
scanf("%d", &kase);
while(kase--){
scanf("%d%d", &n, &m);
for (i = 1; i <= m; ++i) scanf("%d%d", &u[i], &v[i]);
memset(tag, false, sizeof tag);
memset(num, 0, sizeof num);
scanf("%d", &K);
maxv = -1;
for (i = 1; i <= K; ++i){
scanf("%lld%lld", &pos[i], &val[i]);
tag[pos[i]] = true;
num[pos[i]] = val[i];
for (j = maxv + 1; j < 33; ++j)
if (val[i] >> j & 1) maxv = j;
}
// pr(maxv);
Solve();
for (i = 1; i <= n; ++i) printf("%lld\n", num[i]);
}
return 0;
}