zoukankan      html  css  js  c++  java
  • 洛谷 P4306 [JSOI2010]连通数

    洛谷 P4306 [JSOI2010]连通数

    题目链接:洛谷 P4306 [JSOI2010]连通数

    算法标签: 图论统计

    题目

    题目描述

    度量一个有向图联通情况的一个指标是连通数,指图中可达顶点对个的个数。

    如图

    洛谷 P4306 [JSOI2010]连通数 p1

    顶点 1 可达 1, 2, 3, 4, 5

    顶点 2 可达 2, 3, 4, 5

    顶点 3 可达 3, 4, 5

    顶点 4, 5 都只能到达自身。

    所以这张图的连通数为 14。

    给定一张图,请你求出它的连通数

    输入格式

    输入数据第一行是图顶点的数量,一个正整数N。 接下来N行,每行N个字符。第i行第j列的1表示顶点i到j有边,0则表示无边。

    输出格式

    输出一行一个整数,表示该图的连通数。

    输入输出样例

    输入 #1

    3
    010
    001
    100
    

    输出 #1

    9
    

    说明/提示

    对于100%的数据,N不超过2000。

    题解:

    某机房巨佬JZYshuraK_彧 推荐的题,貌似说有很多做法,不过作为一个蒟蒻,我搬出了许久没有用到的 毒瘤 SPFA,思路是将SPFA中的松弛更新最短路改为连通计数,最终统计(ans)即可。

    大致实现如下(链式前向星存图):

    void spfa(int s)
    {
    	memset(vis, 0, sizeof vis);
    	queue <int> q;
    	q.push(s);
    	vis[s] = 1;
    	while(!q.empty())
    	{
    		int x, y;
    		x = q.front();
    		q.pop();
    		for (int i = head[x]; i; i = nex[i])
    		{
    			y = to[i];
    			if (!vis[y])
    			{
    				q.push(y);
    				vis[y] = 1;
    				ans ++ ;
    			}
    		}
    	}
    
    }
    

    之后按照操作统计答案即可,不过本题有毒瘤坑点。

    本题坑点:

    1. 所读入矩阵之中没有空格,需要按照字符串读入在处理(被疯狂卡)
    2. 在输出的时候要记录(ans + n),原因在于这道题当中,自身与自身被算作连通,而在跑SPFA时候是没有记录自己的。

    由于一个01串,假设为(011111000001) ,在这道题的题目下可以很简单的处理为(0101)这样一个串,在进行两种操作取最小值。

    仔细分析这两种操作的时候,我们可以得到以下结论:

    • 我们可以将所有中操作找出两种最优的:

      1. 将0放在一边,1放在一边,最终一次转换
      2. 每一个都单独转换
    • 将字符串第0位设为一个1,这样我们只需要统计由某一位为0而前一位为1的个数,这样的答案就是操作的总次数(可以推得无论如何进行操作总次数都一致)。而且我们可以发现无论如何进行操作,最后一次都是转换,所以我们可以得出

      (ans = (cnt - 1) * min(x, y) + y;)

    由此此题得解,注意本题数据需要开long long

    AC代码

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int N = 2020;
    const int M = N * N;
    
    int n, ans, vis[N];
    int tot, to[M], nex[M], head[N];
    
    void add(int x, int y)
    {
    	to[++tot] = y;
    	nex[tot] = head[x];
    	head[x] = tot;
    }
    void spfa(int s)
    {
    	memset(vis, 0, sizeof vis);
    	queue <int> q;
    	q.push(s);
    	vis[s] = 1;
    	while(!q.empty())
    	{
    		int x, y;
    		x = q.front();
    		q.pop();
    		for (int i = head[x]; i; i = nex[i])
    		{
    			y = to[i];
    			if (!vis[y])
    			{
    				q.push(y);
    				vis[y] = 1;
    				ans ++ ;
    			}
    		}
    	}
    
    }
    int main()
    {
    	scanf("%d", &n);
    	char ch[2020];
    	for (int i = 1; i <= n; i ++ )
    	{
    		scanf("%s", ch + 1);
    		for (int j = 1; j <= n; j ++ )
    		{
    			if (ch[j] == '1')
    				add(i, j);
    		}
    	}
    	for (int i = 1; i <= n; i ++ )
    		spfa(i);
    
    	printf("%d", ans + n);
    	return 0;
    }
    
  • 相关阅读:
    查看 Oracle 是32位还是64位的方法
    Oracle 查看 对象 持有 锁 的情况
    Oracle 11.2.0.3 Patchset
    Oracle 升级10.2.0.5.4 OPatch 报错Patch 12419392 Optional component(s) missing 解决方法
    Oracle 11.2.0.1 升级到 11.2.0.3 示例
    Oracle 安装OEM 报错: 无法对所有EM 相关账户解锁 解决方法
    Oracle sessions,processes 和 transactions 参数 关系 说明
    Oracle 11.2.0.1 升级到 11.2.0.3 示例
    Oracle 查看 对象 持有 锁 的情况
    Oracle Database Appliance
  • 原文地址:https://www.cnblogs.com/littleseven777/p/11851759.html
Copyright © 2011-2022 走看看