zoukankan      html  css  js  c++  java
  • hdoj 3861 The King’s Problem【强连通缩点建图&&最小路径覆盖】

    The King’s Problem

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
    Total Submission(s): 2259    Accepted Submission(s): 795


    Problem Description
    In the Kingdom of Silence, the king has a new problem. There are N cities in the kingdom and there are M directional roads between the cities. That means that if there is a road from u to v, you can only go from city u to city v, but can’t go from city v to city u. In order to rule his kingdom more effectively, the king want to divide his kingdom into several states, and each city must belong to exactly one state. What’s more, for each pair of city (u, v), if there is one way to go from u to v and go from v to u, (u, v) have to belong to a same state. And the king must insure that in each state we can ether go from u to v or go from v to u between every pair of cities (u, v) without passing any city which belongs to other state.
      Now the king asks for your help, he wants to know the least number of states he have to divide the kingdom into.
     
    Input
    The first line contains a single integer T, the number of test cases. And then followed T cases.

    The first line for each case contains two integers n, m(0 < n <= 5000,0 <= m <= 100000), the number of cities and roads in the kingdom. The next m lines each contains two integers u and v (1 <= u, v <= n), indicating that there is a road going from city u to city v.
     
    Output
    The output should contain T lines. For each test case you should just output an integer which is the least number of states the king have to divide into.
     
    Sample Input
    1
    3 2
    1 2
    1 3
     
    Sample Output
    2
     
    题意:一个国王想把他的王国(n个城市,m条路)分成若干个州,要求:如果两个城市u,v之间有路(u,v)和(v,u)则这两个城市必须在同一个州中,且任意 两个州之间要有路;现在问你   国王最少要将王国分成多个州
     题解:首先求scc缩点建新图,之后,因为有的scc之间有边相连,即可以匹配,所以我们找出新图的最大匹配数,求出最小路径覆盖:用最少的边来覆盖所有的点
    #include<stdio.h>
    #include<string.h>
    #include<stack>
    #include<queue>
    #include<vector>
    #include<algorithm>
    #define MAX 5200
    #define MAXM 200100
    using namespace std;
    vector<int>newmap[MAX];
    vector<int>scc[MAX];
    int sccno[MAX];
    int in[MAX],out[MAX];
    int scccnt,dfsclock;
    int n,m;
    int low[MAX],dfn[MAX];
    int instack[MAX];
    int ans,head[MAX];
    int vis[MAX],city[MAX];
    stack<int>s;
    struct node
    {
    	int beg,end,next;
    }edge[MAXM];
    void init()
    {
    	ans=0;
    	memset(head,-1,sizeof(head));
    }
    void add(int u,int v)
    {
    	edge[ans].beg=u;
    	edge[ans].end=v;
    	edge[ans].next=head[u];
    	head[u]=ans++;
    }
    void getmap()
    {
    	int a,b;
    	while(m--)
    	{
    		scanf("%d%d",&a,&b);
    		add(a,b);
    	}
    }
    void tarjan(int u)
    {
    	int v,i,j;
    	low[u]=dfn[u]=++dfsclock;
    	s.push(u);
    	instack[u]=1;
    	for(i=head[u];i!=-1;i=edge[i].next)
    	{
    		v=edge[i].end;
    		if(!dfn[v])
    		{
    			tarjan(v);
    			low[u]=min(low[u],low[v]);
    		}
    		else if(instack[v])
    		    low[u]=min(low[u],dfn[v]);
        }
        if(dfn[u]==low[u])
        {
        	scccnt++;
        	while(1)
        	{
        		v=s.top();
        		s.pop();
        		instack[v]=0;
        		sccno[v]=scccnt;
        		if(v==u)
        		    break;
        	}
        }
    }
    void find(int l,int r)
    {
    	memset(low,0,sizeof(low));
    	memset(dfn,0,sizeof(dfn));
    	memset(instack,0,sizeof(instack));
    	memset(sccno,0,sizeof(sccno));
    	dfsclock=scccnt=0;
    	for(int i=l;i<=r;i++)
    	{
    		if(!dfn[i])
    		    tarjan(i);
    	}
    }
    void suodian()
    {
    	find(1,n);
    	for(int i=1;i<=scccnt;i++)
    		newmap[i].clear();
    	memset(in,0,sizeof(in));
    	memset(out,0,sizeof(out));
    	int u,v,i,j;
    	for(i=0;i<ans;i++)
    	{
    		u=sccno[edge[i].beg];
    		v=sccno[edge[i].end];
    		if(u!=v)
    		{
    			newmap[u].push_back(v);
    			in[v]++;
    			out[u]++;
    		}		
    	}
    }
    int query(int x)
    {
    	int i,j;
    	for(i=0;i<newmap[x].size();i++)
    	{
    		int y=newmap[x][i];
    		if(!vis[y])
    		{
    			vis[y]=1;
    			if(city[y]==0||query(city[y]))
    			{
    				city[y]=x;
    				return 1;
    			}
    		}
    	}
    	return 0;
    }
    void solve()
    {
    	int i,j;
    	int sum=0;
    	memset(city,0,sizeof(city));
    	for(i=1;i<=scccnt;i++)
    	{
    		memset(vis,0,sizeof(vis));
    		if(query(i))
    		   sum++;
    	}
    	printf("%d
    ",scccnt-sum);//最小路径覆盖=顶点数-最大匹配数 
    }
    int main()
    {
    	int t;
    	scanf("%d",&t);
    	while(t--)
    	{
    		scanf("%d%d",&n,&m);
    		init();
    		getmap();
    		suodian();
    		solve();
    	}
    	return 0;
    }
    

      

     
  • 相关阅读:
    RxJava系列7(最佳实践)
    异步编程 z
    利用WCF的双工通讯实现一个简单的心跳监控系统 z
    c#深拷贝
    MEF load plugin from directory
    C# 文件操作 把文件读取到字节数组
    code md5
    gridview转成EXCEL文件保存(多页)
    Getting started with SciPy for .NET
    IronPython调用C# DLL函数方法
  • 原文地址:https://www.cnblogs.com/tonghao/p/4915090.html
Copyright © 2011-2022 走看看