zoukankan      html  css  js  c++  java
  • 洛谷 P2746/AcWing 367 [USACO5.3]校园网Network of Schools

    好久没更了,更一下~

    这题真的胡乱瞎写,WA * 3

    零、原题链接

    luogu

    AcWing

    一、简要题意

    给定一个具有(n) 个点的有向图,需要完成两个任务:

    Task 1 求出这个图至少要给几个点信息,利用有向边的传递关系,可传递至每一个节点。

    Task 2 求出这个图至少要添加几条有向边,使得这个图变成只有一个包含所有点的连通分量。

    (2 ≤ n ≤ 100)

    二、解法

    Task 1

    这个任务很简单,将该图缩完点后求出有多少个入度为(0) 的点即可。

    证明:

    因为所有入度不为(0) 的点一定会有从其他点向它传输的边,所以全部汇集上去,只有入度为(0) 的点没有其他点传递信息给它。

    Task 2

    这个是上一个任务的升级版。

    如果想要变成一个大的连通分量,肯定需要将所有入度/出度为(0) 的点全部改掉。

    所以添加最少的方法就是把一个出度为(0) 的点连向一个入度为0的点,这样一下可以改变(2) 个状态。

    三、code

    缩点使用tarjan算法。

    注意本题的输入格式较为奇怪。

    // by pjx Feb.
    #include <iostream>
    #include <cstdlib>
    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <cstring>
    #include <queue>
    #include <stack>
    #define REP(i, x, y) for(register int i = x; i < y; i++)
    #define rep(i, x, y) for(register int i = x; i <= y; i++)
    #define PER(i, x, y) for(register int i = x; i > y; i--)
    #define per(i, x, y) for(register int i = x; i >= y; i--)
    using namespace std;
    const int N = 105;                                 
    int n, totin, totout;
    int dfn[N], low[N], timetag;
    int b[N];
    int in[N], out[N];
    int sta[N], top;
    int cnt, id[N], len[N], ans1, ans2;
    vector <int> g[N];
    void tarjan(int x)//tarjan模板,下面的//行都是我第一遍写错的 
    {
    	timetag++;//
    	dfn[x] = timetag;
    	low[x] = timetag;
    	sta[++top] = x;
    	b[x] = 1;
    	for(int i = 0; i < g[x].size(); i++)
    	{
    		int y = g[x][i];
    		if(!dfn[y])
    		{
    			tarjan(y);
    			low[x] = min(low[x], low[y]);//
    		}
    		else if(b[y] == 1)
    		{
    			low[x] = min(low[x], dfn[y]);
    		}
    	}	
    	if(dfn[x] == low[x])
    	{
    		cnt++;
    		int y = sta[top];
    		top--;
    		b[y] = 0;
    		id[y] = cnt;
    		len[cnt]++;//
    		while(x != y)
    		{
    			y = sta[top];
    			top--;
    			b[y] = 0;
    			id[y] = cnt;
    			len[cnt]++;
    		}
    	}
    }
    int main()
    {
    	cin >> n;
    	rep(i, 1, n)
    	{
    		int x;
    		cin >> x;
    		while(x != 0)
    		{
    			g[i].push_back(x);
    			cin >> x;
    		}
    	}
    	rep(i, 1, n)
    	{
    		if(!dfn[i])
    		{
    			tarjan(i);
    		}
    	}
    	rep(i, 1, n)//注意这里是n(WA的教训) 
    	{
    		for(int j = 0; j < g[i].size(); j++)
    		{
    			int y = g[i][j];
    			int ida = id[i];
    			int idb = id[y];
    			if(ida != idb)
    			{
    				in[idb]++;
    				out[ida]++;
    			}
    		}
    	}
    	if(cnt == 1)
    	{
    		cout << "1" << endl;
    		cout << "0";
    		return 0;
    	}
    	rep(i, 1, cnt)
    	{
    		if(!in[i])//统计入度为0的点个数 
    		{
    			totin++;
    		}
    		if(!out[i])//统计出度为0的点个数 
    		{
    			totout++;
    		}
    	}
    	cout << totin << endl; //Task 1,求入度节点个数 
    	cout << max(totin, totout);//Task 2,求最少添加多少次有向边可以得到只有一个连通分量 
    	return 0;
    }
    
    
    
  • 相关阅读:
    IntrospectorCleanupListener作用
    买新车流程
    EXCEL-表格安全性:加密给与不同操作权限、表格怎么不让别人复制粘贴?
    全球安全帽品牌推荐整理
    Oracle-SQL语句的语法顺序和执行顺序
    Oracle-除了会排序,你对ORDER BY的用法可能一无所知!
    EXCEL——排序函数RANK,6种花式使用技巧
    常用云盘总结
    关于运算符结合顺叙的一些小探索
    类继承小总结
  • 原文地址:https://www.cnblogs.com/pjxpjx/p/14402949.html
Copyright © 2011-2022 走看看