zoukankan      html  css  js  c++  java
  • 687E: TOF

    Codeforces Round #360 Editorial [+ Challenges!]


    E. TOF
    time limit per test
    1 second
    memory limit per test
    256 megabytes
    input
    standard input
    output
    standard output

    Today Pari gave Arya a cool graph problem. Arya wrote a non-optimal solution for it, because he believes in his ability to optimize non-optimal solutions. In addition to being non-optimal, his code was buggy and he tried a lot to optimize it, so the code also became dirty! He keeps getting Time Limit Exceeds and he is disappointed. Suddenly a bright idea came to his mind!

    Here is how his dirty code looks like:

    dfs(v)
    {
         set count[v] = count[v] + 1
         if(count[v] < 1000)
         {
              foreach u in neighbors[v]
              {
                   if(visited[u] is equal to false)
                   {
                        dfs(u)
                   }
                   break
              }
         }
         set visited[v] = true
    }
    
    main()
    {
         input the digraph()
         TOF()
         foreach 1<=i<=n
         {
              set count[i] = 0 , visited[i] = false
         }
         foreach 1 <= v <= n
         {
              if(visited[v] is equal to false)
              {
                   dfs(v)
              }
         }
         ... // And do something cool and magical but we can't tell you what!
    }
    

    He asks you to write the TOF function in order to optimize the running time of the code with minimizing the number of calls of the dfs function. The input is a directed graph and in the TOF function you have to rearrange the edges of the graph in the list neighbors for each vertex. The number of calls of dfs function depends on the arrangement of neighbors of each vertex.

    Input

    The first line of the input contains two integers n and m (1 ≤ n, m ≤ 5000) — the number of vertices and then number of directed edges in the input graph.

    Each of the next m lines contains a pair of integers ui and vi (1  ≤  ui,  vi  ≤  n), meaning there is a directed edge in the input graph.

    You may assume that the graph won't contain any self-loops and there is at most one edge between any unordered pair of vertices.

    Output

    Print a single integer — the minimum possible number of dfs calls that can be achieved with permuting the edges.

    Examples
    Input
    3 3
    1 2
    2 3
    3 1
    
    Output
    2998
    
    Input
    6 7
    1 2
    2 3
    3 1
    3 4
    4 5
    5 6
    6 4
    
    Output
    3001
    
    



    Hint: What the actual problem is

    Looking at the code in the statement, you can see only the first edge in neighbors of each node is important. So for each vertex with at least one outgoing edge, you have to choose one edge and ignore the others. After this the graph becomes in the shape of some cycles with possible branches, and some paths. The number of dfs calls equals to 998 × ( sum of sizes of cycles ) + n +  number of cycles.

    Solution

    The goal is to minimize the sum of cycle sizes. Or, to maximize the number of vertices which are not in any cycle. Name them good vertices.

    • If there exists a vertex v without any outgoing edge, we can make all of the vertices that v is reachable from them good. Consider the dfs-tree from v in the reverse graph. You can choose the edge from this tree as the first edge in neighbors[u], in order to make all of these vertices good.

    • Vertices which are not in the sink strongly connected components could become good too, by choosing the edges from a path starting from them and ending in a sink strongly connected component.

    • In a sink strongly connected component, there exists a path from every vertex to others. So we can make every vertex good except a single cycle, by choosing the edges in the paths from other nodes to this cycle and the cycle edges.

    So, every vertices could become good except a single cycle in every sink strongly connected component. And the length of those cycles must be minimized, so we can choose the smallest cycle in every sink strongly connected component and make every other vertices good. Finding the smallest cycle in a graph with n-vertex and m edges could be done in O(n(n + m)) with running a BFS from every vertex, so finding the smallest cycle in every sink strongly connected component is O(n(n + m)) overall.


    C++ code

    //     . .. ... .... ..... be name khoda ..... .... ... .. .     \
    
    #include <bits/stdc++.h>
    using namespace std;
    
    
    inline int in() { int x; scanf("%d", &x); return x; }
    const int N = 5005;
    
    int comp[N], bfsDist[N], bfsPar[N];
    vector <int> g[N], gR[N];
    bool mark[N], inCycle[N];
    
    bool dfs(int v, vector <int> *g, vector <int> &nodes)
    {
    	mark[v] = 1;
    	for(int u : g[v])
    		if(!mark[u])
    			dfs(u, g, nodes);
    	nodes.push_back(v);
    }
    
    int findSmallestCycle(vector <int> vs)
    {
    	vector <int> cycle;
    	for(int root : vs)
    	{
    		for(int v : vs)
    		{
    			bfsDist[v] = 1e9;
    			bfsPar[v] = -1;
    		}
    		bfsDist[root] = 0;
    		queue <int> q;
    		q.push(root);
    		bool cycleFound = 0;
    		while(q.size() && !cycleFound)
    		{
    			int v = q.front();
    			q.pop();
    			for(int u : g[v])
    			{
    				if(u == root)
    				{
    					cycleFound = 1;
    					int curLen = bfsDist[v];
    					if(cycle.empty() || curLen < cycle.size())
    					{
    						cycle.clear();
    						for(; v != -1; v = bfsPar[v])
    							cycle.push_back(v);
    					}
    					break;
    				}
    				if(bfsDist[u] > bfsDist[v] + 1)
    				{
    					bfsDist[u] = bfsDist[v] + 1;
    					bfsPar[u] = v;
    					q.push(u);
    				}
    			}
    		}
    	}
    	return cycle.size();
    }
    
    int main()
    {
    	int n, m;
    	cin >> n >> m;
    	for(int i = 0; i < m; i++)
    	{
    		int u = in() - 1;
    		int v = in() - 1;
    		g[u].push_back(v);
    		gR[v].push_back(u);
    	}
    	vector <int> order;
    	for(int i = 0; i < n; i++)
    		if(!mark[i])
    			dfs(i, g, order);
    
    	fill(mark, mark + n, 0);
    	fill(comp, comp + n, -1);
    	int inCycle = 0, nCycle = 0;
    	for(; order.size(); order.pop_back())
    	{
    		int v = order.back();
    		if(mark[v])
    			continue;
    		vector <int> curComp;
    		dfs(v, gR, curComp);
    		bool isSink = true;
    		for(int u : curComp)
    			comp[u] = v;
    		for(int u : curComp)
    			for(int k = 0; k < g[u].size(); k++)
    				if(comp[g[u][k]] != v)
    					isSink = false;
    		if(isSink)
    		{
    			int x = findSmallestCycle(curComp);
    			if(x > 0)
    			{
    			    nCycle++;
    			    inCycle += x;
    			}
    		}
    	}
    	cout << 999 * inCycle + (n - inCycle) + nCycle << endl;
    
    }




    原文链接:Codeforces Round #360 Editorial [+ Challenges!] - Codeforces


  • 相关阅读:
    qq划屏幕红包程序
    【图文教程】小米4如何获取触动精灵悬浮窗权限
    //6小时更新一次首页
    USBWebServer 中文便携版 快速搭建 PHP/MySQL 网站服务器环境
    【jquery】Validform,一款不错的 jquery 表单验证插件
    【html】关于锚点的一些事
    【css】关于 hr 在各浏览器中的问题
    【jquery】fancybox 是一款优秀的 jquery 弹出层展示插件
    【jquery】ajax 请求成功后新开窗口被拦截解决方法
    【html5】html5 本地存储
  • 原文地址:https://www.cnblogs.com/tigerisland/p/7564662.html
Copyright © 2011-2022 走看看