HDU 3844 Mining Your Own Business(割点,变形,开栈,经典)

题意:给出一个连通图,要求将某些点涂黑,使得无论哪个点(包括相关的边)撤掉后能够成功使得剩下的所有点能够到达任意一个涂黑的点,颜料不多,涂黑的点越少越好,并输出要涂几个点和有多少种涂法。

思路:

  要使得任意撤掉一个点都能使其他点能够到达黑点,那么点双连通分量能保证这点,那么就在同个点双连通分量内涂黑1个点。但是每个【点双连通分量】都涂吗?太浪费颜料了,那就缩点成树,只需要涂叶子即可,那就找度为1的缩点。但是种数呢?叶子内的点除了割点外都是可以涂黑的,因为如果黑色割点被撤掉,那么叶子中的其他点怎么办?所以不能涂割点,每个黑点有【叶子中的点数-1】种涂法,所有黑店的涂法相乘为第2个结果。

  特殊情况,因为给的是连通图且至少有2个点,那么还可能会出现没有割点的情况(仅1个点双连通分量),那就直接涂黑两个,以防一个黑点被撤掉。

  此题出现的连续的点可能多达10万个,DFS就会爆栈。在C++下可以手动开栈,G++下的还不清楚怎么开。

  1 #pragma comment(linker,"/STACK:102400000,102400000")//开栈
  2 //#include <bits/stdc++.h>
  3 #include <iostream>
  4 #include <cstdio>
  5 #include <cstring>
  6 #include <algorithm>
  7 #include <vector>
  8 #include <unordered_map>
  9 #include <stack>
 10 #define LL long long
 11 #define pii pair<int,int>
 12 using namespace std;
 13 const int N=100000+5;
 14 const int INF=0x7f7f7f7f;
 15 int up;
 16 int low[N], dfn[N];
 17 bool iscut[N];
 18 int dfn_clock, bcc_cnt, bcc_no[N];
 19 unordered_map<int,int> mapp;
 20 stack< pii >  stac;
 21 vector<int> bcc[N], vect[N];
 22
 23 void DFS(int x, int far)//tarjan
 24 {
 25     dfn[x]=low[x]=++dfn_clock;
 26
 27     int chd=0;
 28     for(int i=0; i<vect[x].size(); i++)
 29     {
 30         int t=vect[x][i];
 31         if(!dfn[t])
 32         {
 33             chd++;
 34             stac.push(make_pair(x,t));
 35             DFS(t,x);
 36             low[x]=min( low[x], low[t]);
 37             if(low[t]>=dfn[x])
 38             {
 39                 iscut[x]=true;    //需要标记割点
 40                 bcc[++bcc_cnt].clear();
 41                 while(true)
 42                 {
 43                     int a=stac.top().first;
 44                     int b=stac.top().second;
 45                     stac.pop();
 46                     if(bcc_no[a]!=bcc_cnt)
 47                     {
 48                         bcc[bcc_cnt].push_back(a);
 49                         bcc_no[a]=bcc_cnt;
 50                     }
 51                     if(bcc_no[b]!=bcc_cnt)
 52                     {
 53                         bcc[bcc_cnt].push_back(b);
 54                         bcc_no[b]=bcc_cnt;
 55                     }
 56                     if(a==x&&b==t)    break;
 57                 }
 58             }
 59         }
 60         else if( dfn[t]<dfn[x] && t!=far)
 61         {
 62             stac.push(make_pair(x,t));
 63             low[x]=min(low[x],dfn[t]);
 64         }
 65     }
 66     if(chd==1&&far==0)    iscut[x]=false;        //根
 67 }
 68
 69 void find_bcc(int Case)
 70 {
 71     memset(low,0,sizeof(low));
 72     memset(dfn,0,sizeof(dfn));
 73     memset(iscut,0,sizeof(iscut));
 74     memset(bcc_no,0,sizeof(bcc_no));
 75
 76     dfn_clock=bcc_cnt=0;
 77     for(int i=1; i<=up; i++)    if(!dfn[i])    DFS(i,0);   //深搜
 78     LL ans1=0,ans2=1;
 79
 80     for(int i=1; i<=bcc_cnt; i++)    //统计度为多少
 81     {
 82         int cnt=0;
 83         for(int j=0; j<bcc[i].size(); j++)    if(iscut[bcc[i][j] ])    cnt++;    //有割点就统计连通分量i的度。
 84         if(cnt==1)    ans1++, ans2*=bcc[i].size()-1;
 85     }
 86     if(bcc_cnt==1)    ans1=2,ans2=(LL)bcc[1].size()*(bcc[1].size()-1)/2;
 87     printf("Case %d: %lld %lld\n", Case, ans1, ans2);
 88 }
 89
 90
 91 int main()
 92 {
 93     freopen("input.txt", "r", stdin);
 94     int a, b, n, j=0;
 95     while(scanf("%d",&n), n)
 96     {
 97         mapp.clear();
 98         for(int i=1; i<N; i++)    vect[i].clear();
 99         up=0;
100         for(int i=0; i<n; i++)
101         {
102             scanf("%d%d",&a,&b);
103             if(!mapp[a])    mapp[a]=++up;
104             if(!mapp[b])    mapp[b]=++up;//点号缩小为连续
105
106             vect[mapp[a]].push_back(mapp[b]);
107             vect[mapp[b]].push_back(mapp[a]);
108         }
109         find_bcc(++j);
110     }
111     return 0;
112 }

AC代码

时间: 2024-11-09 21:52:02

HDU 3844 Mining Your Own Business(割点,变形,开栈,经典)的相关文章

HDU 3844 Mining Your Own Business

Mining Your Own Business Time Limit: 1000ms Memory Limit: 32768KB This problem will be judged on HDU. Original ID: 384464-bit integer IO format: %I64d      Java class name: Main John Digger is the owner of a large illudium phosdex mine. The mine is m

hdu 3844 Mining Your Own Business (点双连通分量)

Mining Your Own Business Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1392    Accepted Submission(s): 219 Problem Description John Digger is the owner of a large illudium phosdex mine. The m

hdu4587 求割点变形

http://acm.hdu.edu.cn/showproblem.php?pid=4587 Problem Description Suppose that G is an undirected graph, and the value of stab is defined as follows: Among the expression,G-i, -j is the remainder after removing node i, node j and all edges that are

UVA 1108 - Mining Your Own Business(双连通分量)

UVA 1108 - Mining Your Own Business 题目链接 题意:给定一个连通图,设置一个些安全点,使得其他任意一些节点崩塌后,其他点都能到一个安全点,问安全点最小数量和情况数 思路: #include <cstdio> #include <cstring> #include <vector> #include <stack> #include <map> using namespace std; const int N =

HDU 5643 King&#39;s Game | 约瑟夫环变形

经典约瑟夫环 1 int f[N] ={ 0 }; 2 for(int i=2; i<=n; i++) 3 { 4 f[i] = (f[i-1] + k) % i; 5 } 变形:k是变化的 #include <iostream> #include <stdio.h> #include <string.h> #include <algorithm> #include <stdlib.h> #include <queue> #in

HDU 2448 Mining Station on the Sea 费用流

Mining Station on the Sea Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2123    Accepted Submission(s): 642 Problem Description The ocean is a treasure house of resources and the development o

HDU 2448 Mining Station on the Sea km

#include<cstdio> #include<string> #include<cstring> #include<iostream> #include<map> using namespace std; const int maxn = 105; const int INF = (1<<30)-1; int g[2*maxn][2*maxn]; int f[2*maxn][2*maxn]; int lx[maxn],ly[ma

hdu 5340 最长回文子串变形

http://acm.hdu.edu.cn/showproblem.php?pid=5340 Problem Description Can we divided a given string S into three nonempty palindromes? Input First line contains a single integer T≤20 which denotes the number of test cases. For each test case , there is

HDU 2897 邂逅明下 ( bash 博弈变形

HDU 2897 邂逅明下 ( bash 博弈变形 题目大意 有三个数字n,p,q,表示一堆硬币一共有n枚,从这个硬币堆里取硬币,一次最少取p枚,最多q枚,如果剩下少于p枚就要一次取完.两人轮流取,直到堆里的硬币取完,最后一次取硬币的算输. 解题思路 若 n == k * (p + q), 则 A 必胜 第一次 A 取 p 个, 之后每次 B 取 x 个时, A 取 (p + q - x) 个, 则最后当 B 面对有 p 个硬币的时候, 必输. 若 n == k * (p + q) + left