HDU 5452 Minimum Cut(LCA+DFS)

来源:互联网 发布:网络摄像头的ip自适应 编辑:程序博客网 时间:2024/05/18 12:39

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5452


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 (1t5) 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 (2n20000) and m (n1m200000).
The following n1 lines describe the spanning tree T and each of them contains two integers u and v corresponding to an edge.
Next mn+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
14 51 22 33 41 31 4
 

Sample Output
Case #1: 2
 

Source
2015 ACM/ICPC Asia Regional Shenyang Online

题意:

给出一个图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 0x3f3f3f3fconst int maxn = 80010;const int maxm = 26;int dp[2*maxn][maxm];  //数组开到2*N,因为遍历后序列长度为2*n-1bool 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;}


0 0
原创粉丝点击