hdu3861 強連通分量縮點+二分圖最最小路徑覆蓋
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
Now the king asks for your help, he wants to know the least number of states he have to divide the kingdom into.
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.
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 強連通分量縮點+二分圖最最小路徑覆蓋