Minimum CutTime Limit: 3000/2000 MS (Java/Others) Memory Limit: 65535/102400 K (Java/Others)Total Submission(s): 658 Accepted Submission(s): 292
Problem Description
Given a simple unweighted graph G (an
undirected graph containing no loops nor multiple edges) with n nodes
and m edges.
Let T be
a spanning tree of G.
We say that a cut in G respects T if it cuts just one edges of T. Since love needs good faith and hypocrisy return for only grief, you should find the minimum cut of graph G respecting the given spanning tree T.
Input
The input contains several test cases.
The first line of the input is a single integer t (1≤t≤5) which is the number of test cases. Then t test cases follow. Each test case contains several lines. The first line contains two integers n (2≤n≤20000) and m (n−1≤m≤200000). The following n−1 lines describe the spanning tree T and each of them contains two integers u and v corresponding to an edge. Next m−n+1 lines describe the undirected graph G and each of them contains two integers u and v corresponding to an edge which is not in the spanning tree T.
Output
For each test case, you should output the minimum cut of graph G respecting
the given spanning tree T.
Sample Input
Sample Output
|
题意:给出一个图G和它的一个生成树T。现在要求删除生成树上的一条边和若干条其他边,使得图不连通。求能删除的最小边数。
思路:LCA 修改、记录每个点被覆盖环的次数,最后找出最小的覆盖次数+1就可以了。
AC代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#define MAXN 20000+10
#define MAXM 200000+10
#define INF 0x3f3f3f3f
using namespace std;
struct Edge
{
int to, next;
};
Edge edge[MAXM<<1];
int head[MAXN], edgenum;
int depth[MAXN];
int pre[MAXN];//记录节点前驱
int num[MAXN];//记录节点被环覆盖的次数
int N, M;
void init()
{
edgenum = 0;
memset(head, -1, sizeof(head));
}
void addEdge(int u, int v)
{
edge[edgenum].to = v;
edge[edgenum].next = head[u];
head[u] = edgenum++;
}
void getMap()
{
init();
scanf("%d%d", &N, &M);
int a, b;
for(int i = 1; i < N; i++)
{
num[i] = 0;
scanf("%d%d", &a, &b);
addEdge(a, b);
addEdge(b, a);
}
}
void DFS(int u, int fa, int d)
{
depth[u] = d;//记录深度
for(int i = head[u]; i != -1; i = edge[i].next)
{
int v = edge[i].to;
if(v == fa) continue;
pre[v] = u;
DFS(v, u, d+1);
}
}
void find_depth()
{
memset(depth, 0, sizeof(depth));
memset(pre, 0, sizeof(pre));
DFS(1, -1, 0);
}
int k = 1;
void work(int e1, int e2)
{
while(1)//到达LCA
{
if(depth[e1] > depth[e2])
{
num[e1]++;
e1 = pre[e1];
}
else
{
num[e2]++;
e2 = pre[e2];
}
if(e1 == e2)
{
num[e1]++;
break;
}
}
}
void solve()
{
find_depth();
int a, b;
for(int i = 0; i < M-N+1; i++)
{
scanf("%d%d", &a, &b);
if(a == b)
{
num[a]++;
continue;
}
work(a, b);//对树边处理
}
int ans = INF;
for(int i = 1; i <= N; i++)//求最小次数 环覆盖
ans = min(num[i]+1, ans);
printf("Case #%d: %d\n", k++, ans);
}
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
getMap();
solve();
}
return 0;
}
树链剖分:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <string>
#define INF 0x3f3f3f3f
#define eps 1e-8
#define MAXN (20000+10)
#define MAXM (300000+10)
#define Ri(a) scanf("%d", &a)
#define Rl(a) scanf("%lld", &a)
#define Rf(a) scanf("%lf", &a)
#define Rs(a) scanf("%s", a)
#define Pi(a) printf("%d\n", (a))
#define Pf(a) printf("%.2lf\n", (a))
#define Pl(a) printf("%lld\n", (a))
#define Ps(a) printf("%s\n", (a))
#define W(a) while((a)--)
#define CLR(a, b) memset(a, (b), sizeof(a))
#define MOD 1000000007
#define LL long long
#define lson o<<1, l, mid
#define rson o<<1|1, mid+1, r
#define ll o<<1
#define rr o<<1|1
#define PI acos(-1.0)
#pragma comment(linker, "/STACK:102400000,102400000")
#define fi first
#define se second
using namespace std;
struct Edge{
int from, to, next;
};
Edge edge[MAXN<<1];
int head[MAXN], edgenum;
void init(){
edgenum = 0; CLR(head, -1);
}
void addEdge(int u, int v)
{
Edge E = {u, v, head[u]};
edge[edgenum] = E;
head[u] = edgenum++;
}
int son[MAXN], num[MAXN];
int top[MAXN], pos[MAXN], id;
int dep[MAXN], pre[MAXN];
void DFS1(int u, int fa, int d)
{
dep[u] = d; pre[u] = fa; num[u] = 1; son[u] = -1;
for(int i = head[u]; i != -1; i = edge[i].next)
{
int v = edge[i].to;
if(v == fa) continue;
DFS1(v, u, d+1);
num[u] += num[v];
if(son[u] == -1 || num[son[u]] < num[v])
son[u] = v;
}
}
void DFS2(int u, int T)
{
top[u] = T; pos[u] = ++id;
if(son[u] == -1) return ;
DFS2(son[u], T);
for(int i = head[u]; i != -1; i = edge[i].next)
{
int v = edge[i].to;
if(v == pre[u] || v == son[u]) continue;
DFS2(v, v);
}
}
int ans[MAXN];
void Update(int u, int v)
{
int f1 = top[u], f2 = top[v];
while(f1 != f2)
{
if(dep[f1] < dep[f2])
{
swap(u, v);
swap(f1, f2);
}
ans[pos[f1]]++; ans[pos[u]+1]--;
u = pre[f1], f1 = top[u];
}
if(u == v) return ;
if(dep[u] > dep[v]) swap(u, v);
ans[pos[son[u]]]++; ans[pos[v]+1]--;
}
int main()
{
int t, kcase = 1; Ri(t);
W(t)
{
int n, m; Ri(n); Ri(m); init();
int s, e;
for(int i = 1; i <= n-1; i++)
{
Ri(s); Ri(e);
addEdge(s, e);
addEdge(e, s);
}
DFS1(1, -1, 1); id = 0; DFS2(1, 1);
CLR(ans, 0);
for(int i = n; i <= m; i++)
{
Ri(s); Ri(e);
Update(s, e);
}
int Min = INF;
for(int i = 2; i <= id; i++)
{
ans[i] += ans[i-1];
Min = min(ans[i], Min);
}
printf("Case #%d: %d\n", kcase++, Min+1);
}
return 0;
}