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.
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.
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.
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\n",scccnt-sum);//最小路径覆盖=顶点数-最大匹配数
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
init();
getmap();
suodian();
solve();
}
return 0;
}