1. 程式人生 > >hdu3861 強連通分量縮點+二分圖最最小路徑覆蓋

hdu3861 強連通分量縮點+二分圖最最小路徑覆蓋

必須 sta .html tails XA 強連通分量 amp UC ica

The King’s Problem

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


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

Source 2011 Multi-University Training Contest 3 - Host by BIT 題意轉載自http://www.cnblogs.com/kane0526/archive/2013/07/21/3203992.html

題意:一個有向圖,讓你按規則劃分區域,要求劃分的區域數最少。

規則如下:1、有邊u到v以及有邊v到u,則u,v必須劃分到同一個區域內。2、一個區域內的兩點至少要有一方能到達另一方。3、一個點只能劃分到一個區域內。

解題思路:根據規則1可知必然要對強連通分量進行縮點,縮點後變成了一個弱連通圖。根據規則2、3可知即是要求圖的最小路徑覆蓋。

定義:

最小路徑覆蓋:在圖中找一些路徑(路徑數最少),使之覆蓋了圖中所有的頂點,且每個頂點有且僅和一條路徑有關聯。

最小頂點覆蓋:在圖中找一些點(頂點數最少),使之覆蓋了圖中所有的邊,每條邊至少和一個頂點有關聯。

二分圖:最小頂點覆蓋=最大匹配數。

最小路徑覆蓋=頂點數-最大匹配數。

二分圖最最小路徑覆蓋:https://www.cnblogs.com/justPassBy/p/5369930.html

匈牙利算法:https://blog.csdn.net/dark_scope/article/details/8880547

代碼:

#include<stdio.h>
#include<vector>
#include<stack>
#include<string.h>
using namespace std;
vector<int> s[5050];//
stack<int> st;
int vt[5050];
int cnt,ct;
int low[5050],dfn[5050];
int bl[5050],nd[5050];//例:如果是a-->b,則bl[b]=a;如果a點再經過tarjan算法後屬於第i個集合,nd[a]=i;
struct
{
  int x,y;
}mp[100050];
int min(int a,int b)
{
  if(a<=b)
  return a;
  return b;
}
int tarjan(int a)//tarjan算法
{
  int i,j;
  low[a]=dfn[a]=cnt++;
  vt[a]=1;
  st.push(a);
  for(i=0;i<s[a].size();i++)
  {
    int u=s[a][i];
    if(!dfn[u])
    {
      tarjan(u);
      low[a]=min(low[a],low[u]);
    }
    else if(vt[u])
    low[a]=min(low[a],dfn[u]);
  }
  if(low[a]==dfn[a])
  {
    int x;
    ct++;
    do//為縮點作準備
    {
      x=st.top();
      vt[x]=0;
      nd[x]=ct;
      st.pop();
    }while(x!=a);
  }
  return 0;
}
int find(int a)//匈牙利算法
{
  int i,j;
  for(i=0;i<s[a].size();i++)
  {
    int u=s[a][i];
    if(!vt[u])
    {
      vt[u]=1;
      if(bl[u]==0||find(bl[u]))
      {
        bl[u]=a;
        //printf("www%d %d\n",bl[u],u);
        return 1;
      }
    }
  }
  return 0;
}
int main()
{
  int n,m,t;
  int i,j;
  int a,b,sum;
  scanf("%d",&t);
while(t--)
{
  memset(dfn,0,sizeof(dfn));
  memset(vt,0,sizeof(vt));
  memset(bl,0,sizeof(bl));
  ct=0;
  cnt=1;
  scanf("%d%d",&n,&m);
  for(i=1;i<=n;i++)
  s[i].clear();
  for(i=1;i<=m;i++)
  {
    scanf("%d%d",&mp[i].x,&mp[i].y);
    s[mp[i].x].push_back(mp[i].y);
  }
  for(i=1;i<=n;i++)
  if(!dfn[i])tarjan(i);
  sum=0;
  for(i=1;i<=n;i++)
  s[i].clear();
  for(i=1;i<=m;i++)//縮點並重新制圖
  {
    int u,v;
    u=nd[mp[i].x];
    v=nd[mp[i].y];
    if(u!=v)
    s[u].push_back(v);
  }
  for(i=1;i<=ct;i++)
  {
    memset(vt,0,sizeof(vt));
    if(find(i))
    sum++;
  }
  printf("%d\n",ct-sum);
  }
  return 0;
}

例:

6 6

1 2

2 3

3 1

4 1

5 2

6 3

3

10 11

1 2

2 3

3 1

3 4

4 5

5 6

6 7

7 5

10 9

9 8

8 4

2

hdu3861 強連通分量縮點+二分圖最最小路徑覆蓋