1429 - Assassin`s Creed (II)
![]() ![]() | PDF (English) | Statistics | Forum |
Time Limit: 4 second(s) | Memory Limit: 32 MB |
Ezio needs to kill N targets located in N different cities. The cities are connected by some one way roads. As time is short, Ezio can send a massage along with the map to the assassin's bureau to send some assassins who will start visiting cities and killing the targets. An assassin can start from any city, he may visit any city multiple times even the cities that are already visited by other assassins. Now Ezio wants to find the minimum number of assassins needed to kill all the targets.
Input
Input starts with an integer T (≤ 70), denoting the number of test cases.
Each case starts with a blank line. Next line contains two integers N (1 ≤ N ≤ 1000) and M (0 ≤ M ≤ 10000), where N denotes the number of cities and M denotes the number of one way roads. Each of the next M lines contains two integers u v (1 ≤ u, v ≤ N, u ≠ v) meaning that there is a road from u to v. Assume that there can be at most one road from a city u to v.
Output
For each case, print the case number and the minimum number of assassins needed to kill all targets.
Sample Input | Output for Sample Input |
3
5 4 1 2 1 3 4 1 5 1
7 0
8 8 1 2 2 3 3 4 4 1 1 6 6 7 7 8 8 6 | Case 1: 2 Case 2: 7 Case 3: 2 |
Note
Dataset is huge, use faster I/O methods.
题目大意:有N个地方,每个地方有一个人,要派出忍者刺杀他们,每个忍者可以走重复的城市,问最少派出多少个忍者(有向图)
刚看到题的时候想着是最小路径覆盖,就直接写了二分图但是不对,看了题目才发现,这是有向图,有环,而且是可相交路径覆盖。那就不能单纯地写一个二分图匹配。首先要求闭包,详见最小路径覆盖问题值得注意的地方。再对这个图跑一遍tarjan求出所有的环,将其缩点,最后建新图跑一遍二分图匹配即可
#include<iostream>
#include<cstdio>
#include<cstring>
#include<stack>
#include<queue>
#include<vector>
using namespace std;
const int maxn=2010;
const int maxm=1e6+7;
struct Node
{
int to;
int next;
}edge[maxm];
struct Match
{
int to;
int next;
}match_edge[maxm];
int match_cnt;
int match_head[maxn];
int cnt;
int iindex;
int scc_cnt;
int head[maxn];
int dfn[maxn];
int low[maxn];
bool vis[maxn];
int belong[maxn];
int match[maxn];
vector<int> G[maxn];
stack<int> sta;
void init()
{
memset(head,-1,sizeof(head));
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(belong,0,sizeof(belong));
memset(match_head,-1,sizeof(match_head));
while(!sta.empty()) sta.pop();
for(int i=0;i<maxn;i++) G[i].clear();
match_cnt=scc_cnt=cnt=iindex=0;
return;
}
void add(int u,int v)
{
edge[cnt].to=v;
edge[cnt].next=head[u];
head[u]=cnt++;
return;
}
void addedge(int u,int v)
{
match_edge[match_cnt].to=v;
match_edge[match_cnt].next=match_head[u];
match_head[u]=match_cnt++;
return;
}
void tarjan(int node)
{
dfn[node]=low[node]=++iindex;
sta.push(node);
vis[node]=true;
for(int i=head[node];~i;i=edge[i].next)
{
int v=edge[i].to;
if(!dfn[v])
{
tarjan(v);
low[node]=min(low[node],low[v]);
}
else if(vis[v])
{
low[node]=min(low[node],dfn[v]);
}
}
if(dfn[node]==low[node])
{
int v=-1;
++scc_cnt;
while(node!=v)
{
v=sta.top();
sta.pop();
vis[v]=false;
belong[v]=scc_cnt;
}
}
return;
}
void bfs(int node)
{
queue<int> que;
int len=G[node].size();
vis[node]=true;
for(int i=0;i<len;i++)
{
int v=G[node][i];
if(vis[v]) continue;
else
{
que.push(v);
vis[v]=true;
add(node,v);
}
}
while(!que.empty())
{
int now=que.front();
que.pop();
int now_len=G[now].size();
for(int i=0;i<now_len;i++)
{
int v=G[now][i];
if(vis[v]) continue;
else
{
vis[v]=true;
que.push(v);
add(node,v);
}
}
}
return;
}
bool dfs(int node)
{
for(int i=match_head[node];~i;i=match_edge[i].next)
{
int v=match_edge[i].to;
if(!vis[v])
{
vis[v]=true;
if(match[v]==-1||dfs(match[v]))
{
match[v]=node;
return true;
}
}
}
return false;
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int test;
scanf("%d",&test);
for(int cas=1;cas<=test;cas++)
{
init();
int n,m;
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
G[u].push_back(v);
}
for(int i=1;i<=n;i++)
{
memset(vis,false,sizeof(vis));
bfs(i);
}
memset(vis,false,sizeof(vis));
for(int i=1;i<=n;i++)
{
if(!dfn[i])
{
tarjan(i);
}
}
for(int node=1;node<=n;node++)
{
for(int i=head[node];~i;i=edge[i].next)
{
int v=edge[i].to;
if(belong[node]!=belong[v])
{
addedge(belong[node],belong[v]);
}
}
}
int ans=0;
memset(match,-1,sizeof(match));
for(int i=1;i<=scc_cnt;i++)
{
memset(vis,false,sizeof(vis));
if(dfs(i))
{
ans++;
}
}
printf("Case %d: %d\n",cas,scc_cnt-ans);
}
return 0;
}