FOJ 211. Explosive Materials

競程作業,2015 TOPC Problem E:FOJ-211

題目是中文的,真開心
就是有個人要把東西分成兩堆
但是幾組配對是不能放在同一堆的

如果把所有配對連起來的話會出現很多棵樹
只要這些樹上面有奇數的環,就會炸炸炸
檢查的方法就是 BFS 然後邊記每個點跟 root 的距離
如果記距離的時候發現有已經記過的點他的距離跟剛剛的點一樣
代表說有出現奇數的環,所以會炸炸炸

至於找到背包需要多大的話就是 BFS 的時候要順便記存下每棵樹需要多大的空間
就是換成二分圖的模式兩邊各有幾個點

最後會有一堆這種數組
然後用 dp 找出把這些數組疊起來最小的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# include <bits/stdc++.h>
using namespace std;

# define ll long long
# define ui unsigned int
# define ull unsigned long long
# define INF 1023456789
# define jizz cin.tie(0);ios_base::sync_with_stdio(0);

vector<vector<int>> dpt(1004, vector<int>(1004));
int mid;
int dp(int now, int cha, vector<int> &trees){
if(now==-1) return 0;
if(dpt[now][cha]) return dpt[now][cha];
int tmp1 = dp(now-1, cha+trees[now], trees) + trees[now] - mid;
int tmp2 = dp(now-1, cha, trees) - mid;
if(tmp1+cha>0) tmp1 = -1e9;
if(tmp2+cha>0) tmp2 = -1e9;
return dpt[now][cha] = max(tmp1 + mid, tmp2 + mid);
}

bool bfs(int s, pair<int, int> &p, vector<vector<int>> &adj, vector<int> &M){
queue<pair<int, int>> bs;
bs.push(make_pair(s, 1));
while(!bs.empty()){
if(bs.front().second%2) p.first++;
else p.second++;
for(auto& it: adj[bs.front().first]){
if(!M[it]){
M[it] = bs.front().second+1;
bs.push(make_pair(it, bs.front().second+1));
}
else if(M[it]==bs.front().second){
return 1;
}
}
bs.pop();
}
return 0;
}

void solve(){
int n, m, a, b, base=0, tmp, all=0;
bool flag = 0;
cin>>n>>m;
vector<vector<int>> adj(n+1, vector<int>());
vector<int> M(n+1, 0);
vector<int> trees;
for(int i=0; i<m; i++){
cin>>a>>b;
adj[a].push_back(b);
adj[b].push_back(a);
}
for(int i=1; i<=n; i++){
if(!M[i]){
M[i] = 1;
pair<int, int> p;
p.first = 0;
p.second = 0;
flag = bfs(i, p, adj, M);
if(flag) break;
base += min(p.first, p.second);
tmp = abs(p.first-p.second);
all += tmp;
mid = all/2;
trees.push_back(tmp);
}
}
if(flag) cout<<"-1\n";
else{
for(auto &it: dpt){
fill(it.begin(), it.end(), 0);
}
sort(trees.begin(), trees.end());
cout<<all - (dp(trees.size()-1, 0, trees))+base<<"\n";
}
}

int main(){jizz
int t;
cin>>t;
while(t--){
solve();
}
}