zoukankan      html  css  js  c++  java
  • P3225 [HNOI2012]矿场搭建

    好不错的一道题,花了大量知识ac了

    题目链接

    https://www.luogu.com.cn/problem/P3225

    图论的相关定义

    https://www.cnblogs.com/poi-bolg-poi/p/12183166.html
    可直接在这看↓

    题解

    起初做的时候以为,寻找每个割点,在割点形成的联通块中判断。
    每有一个联通块,ans1 ++; 联通块size相乘 得到ans2。
    后来一个点都没过,思路是错误的。

    正解 :

    上边方法的错误在ans1, ans1错了 所以ans2也错了。
    首先我们可以知道,求割点是必要的。
    对于割点形成的点双,有以下几种情况

    • 不存在割点 rt
    • 一个割点 rt

      已标黑割点
    • 多个割点 rt

    之所以分为这三种情况, 是因为所产生的答案计数不同。

    开始分类讨论
    $ 1° $ 不存在割点。

    当出口矿点坍塌的时候,必然有需要另一个矿点可以作为出口.

    每个点双彼此之间由割点连接构成,不存在割点即此点双完全不可到其他点双,需要单独考虑。

    也就是在当前点双中任选两个点作为出口,$ C(n,2) $种可选情况.

    $ 2 ° $ 一个割点。

    当割点所在矿点坍塌时,必然会使图不连通

    当该割点塌陷的时候,图就不会联通,必然要在当前点双里在建一个出口

    如 样例1

    点双$ { $ $ 1,6,2,3,5 $ $ } $ $中,除去1点,皆符合情况。

    $ 3° $ 多个割点。

    因为存在多个割点,任意一个矿点坍塌都不会对图的连通性造成影响

    当当前所在点双的某个割点塌陷后,图依然联通,必然可以走到其他的点双,从其他点双的出口出去,对答案无影响。
    综上所述(雾) 。。。。

    代码

    挺重要的,还是要看看怎么写

    #include<bits/stdc++.h>
    #define clear(a) memset(a, 0, sizeof a)
    using namespace std;
    const int N = 5e2+50;
    struct node{ int next, to; }edge[N<<1];
    int cnt, head[N];
    inline void add(int from, int to) { edge[++cnt] = (node) {head[from], to}, head[from] = cnt;}
    int low[N], dfn[N], visited[N], cut[N];
    int tot, sky, size, num;
    
    void tarjan(int u, int f) {
    	low[u] = dfn[u] = ++tot; int child = 0;
    	for(int i = head[u]; i; i = edge[i].next) {
    		int v = edge[i].to;
    		if(!dfn[v]) {
    			tarjan(v, f), low[u] = min(low[u], low[v]);
    			if(u == f) child ++;
    			if(u != f && low[v] >= dfn[u]) cut[u] = 1;
    		}else low[u] = min(low[u], dfn[v]);
    	}
    	if(u == f && child >= 2) cut[u] = 1;
    }
    void dfs(int u) {
    	size++, visited[u] = sky;
    	for(int i = head[u]; i; i = edge[i].next) {
    		int v = edge[i].to;
    		if(visited[v] != sky && cut[v]) num ++, visited[v] = sky;
    		if(!visited[v] && !cut[v]) dfs(v);
    	}
    }
    
    int main() {
    	int n = 0, m, t = 0;
    	while(1) {
    		clear(head), clear(edge), clear(cut);
    		clear(visited), clear(low), clear(dfn);
    		t++;
    		n = cnt = tot = 0;
    		scanf("%d", &m);
    		if(m == 0) break;
    		for(int i = 1; i <= m; i++) {
    			int a, b; scanf("%d%d", &a, &b);
    			add(a, b), add(b, a);
    			n = max(max(a, b), n);
    		}
    		for(int i = 1; i <= n; i++) if(!dfn[i]) tarjan(i, i);
    		long long ans1 = 0, ans2 = 1;
    		for(int i = 1; i <= n; i++) {
    			if(!visited[i] && !cut[i]) {
    				num = size = 0, sky++,dfs(i);
    				if(num == 0) ans1 += 2, ans2 *= size* (size - 1) / 2;
    				if(num == 1) ans1 ++, ans2 *= size;
    			}
    		}
    		printf("Case %d: %lld %lld
    ", t, ans1, ans2);
    	}
    	return 0;
    }
    
  • 相关阅读:
    ASP.NET登录记住用户名
    .NET枚举类型转为List类型
    display:inline-block 去除间隙
    sublime text 3 常用快捷键 、常用插件
    使用背景图代码
    Photo Shop 修改、维护
    前端协作流程
    Photo Shop切图
    Photo Shop 设置
    Flex 弹性布局
  • 原文地址:https://www.cnblogs.com/skkyk/p/12198395.html
Copyright © 2011-2022 走看看