题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5452
1 4 5 1 2 2 3 3 4 1 3 1 4
Case #1: 2
题意:
给出一个图G,求删除最少的边使的图G变为不连通,所删除的边须有且仅有一条属于图G的生成树T!
PS:
如果一条边 e(u,v) 不属于生成树T,那么对于 u 和 v 来说它连接到其他子树的贡献是1,
所以要num[u]++, num[v]++; (num存的是删除某个点需要删除的边的数量)!
如果e(u,v)这条边不是LCA(u,v)的这个点所要删除的边。那么两个端点的贡献就是2!所以要num[tt]-=2;
代码如下:
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define INF 0x3f3f3f3f const int maxn = 80010; const int maxm = 26; int dp[2*maxn][maxm]; //数组开到2*N,因为遍历后序列长度为2*n-1 bool vis[maxn]; struct edge { int from, to; int next; } e[2*maxn]; int tot,head[maxn]; int cnt; int num[maxn]; void init() { memset(head,-1,sizeof(head)); memset(vis,false,sizeof(vis)); memset(num,0,sizeof(num)); cnt = 0; } void addedge(int u, int v) { e[cnt].from = u; e[cnt].to = v; e[cnt].next = head[u]; head[u] = cnt++; } int ver[2*maxn], R[2*maxn], first[maxn]; //ver:节点编号 R:深度 first:点编号位置 void dfs(int u ,int dep) { vis[u] = true; ver[++tot] = u; first[u] = tot; R[tot] = dep; for(int k=head[u]; k!=-1; k=e[k].next) if( !vis[e[k].to] ) { int v = e[k].to; dfs(v, dep+1); ver[++tot] = u; R[tot] = dep; } } void ST(int n) { for(int i=1; i<=n; i++) dp[i][0] = i; for(int j=1; (1<<j)<=n; j++) { for(int i=1; i+(1<<j)-1<=n; i++) { int a = dp[i][j-1] , b = dp[i+(1<<(j-1))][j-1]; dp[i][j] = R[a]<R[b]?a:b; } } } //中间部分是交叉的。 int RMQ(int l,int r) { int k=0; while((1<<(k+1))<=r-l+1) k++; int a = dp[l][k], b = dp[r-(1<<k)+1][k]; //保存的是编号 return R[a]<R[b]?a:b; } int LCA(int u ,int v) { int x = first[u] , y = first[v]; if(x > y) swap(x,y); int res = RMQ(x,y); return ver[res]; } int DFS(int u,int fa) { for(int i = head[u]; ~i; i = e[i].next) { int v = e[i].to; if(v == fa) continue; DFS(v, u); num[u]+=num[v]; } return 0; } int main() { int t; int cas = 0; int n, m; scanf("%d",&t); while(t--) { init(); scanf("%d%d",&n,&m); int u, v; for(int i = 0; i < n-1; i++) { scanf("%d%d",&u,&v); addedge(u, v); addedge(v, u); } for(int i = n; i <= m; i++) { scanf("%d%d",&u,&v); int tt = LCA(u, v); num[u]++; num[v]++; num[tt]-=2;//一条边两个端点 贡献为2 } DFS(1, 1); int ans = INF; for(int i = 2; i <= n; i++) { ans = min(ans, num[i]+1); } printf("Case #%d: %d\n",++cas,ans); } return 0; }