题目背景
2017.10.11
leoly的选讲题
题目描述
NOI2016开始了,来自全国各省的选手聚集到了绵阳市的n个车站,编号为1到n,每个车站都有一名选手到来。
绵阳市的道路错综复杂,车站之间的路都是单行路。且图中可能存在重边和自环。
大巴车从南山中学出发,经过若干车站,最后回到南山中学。大巴车每经过一个车站,都会接走那个车站里的选手(若该选手还没有被接走)。每个车站和南山中学均双向连通。同一个车站可以经过多辆大巴车,一辆大巴车也可以多次经过同一个车站。
南山中学的老师希望用尽量少的大巴车,接走所有车站的选手,请你告诉南山中学的老师至少需要多少辆大巴车。
输入输出格式
输入格式:
第一行一个整数t,表示数据组数。
对于每组数据:
第一行两个整数n,m。
接下来m行,每行两个整数x、y,表示编号为x的车站到编号为y的车站有一条单行路。
输出格式:
t行,每行对应该组数据的答案。
输入输出样例
输入样例#1: 复制
1
4 3
1 2
2 3
2 4
输出样例#1: 复制
2
说明
30%的数据,1<=n<=10,0<=m<=20
100%的数据,1<=t<=10,1<=n<=200,0<=m<=1000
时间限制:1s
内存限制:128M
不得不%leoly orz 这题带环 然而我对最少路径覆盖一开始理解不清楚 导致没有tarjan 就做 死的很惨
所以只需要tarjan缩环 然后再floyd传递闭包 最后跑一个最大流 算出答案即可
#include<queue>
#include<cstdio>
#include<stack>
#include<cstring>
#include<algorithm>
#define inf 0x3f3f3f3f
#define N 2200
using namespace std;
inline char gc(){
static char now[1<<16],*S,*T;
if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;}
return *S++;
}
inline int read(){
int x=0;char ch=gc();
while(ch<'0'||ch>'9') ch=gc();
while(ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=gc();}
return x;
}
struct node{
int y,z,next;
}data[N*N],data1[N*N];
int h[N],level[N],num=1,t,T,mp[N][N],n,m,cnt,b[N],dfn[N],low[N],stackf[N],s,h1[N];
inline void insert1(int x,int y,int z){
data[++num].y=y;data[num].z=z;data[num].next=h[x];h[x]=num;
data[++num].y=x;data[num].z=0;data[num].next=h[y];h[y]=num;
}
inline bool bfs(){
queue<int>q;q.push(0);memset(level,0,sizeof(level));level[0]=1;
while(!q.empty()){
int x=q.front();q.pop();
for (int i=h[x];i;i=data[i].next){
int y=data[i].y,z=data[i].z;
if(level[y]||!z) continue;level[y]=level[x]+1;q.push(y);if (y==T) return 1;
}
}return 0;
}
inline int dfs(int x,int s){
if (x==T) return s;int ss=s;
for (int i=h[x];i;i=data[i].next){
int y=data[i].y,z=data[i].z;
if (level[x]+1==level[y]&&z){
int xx=dfs(y,min(z,s));if(!xx) level[y]=0;
s-=xx;data[i].z-=xx;data[i^1].z+=xx;if (!s) return ss;
}
}return ss-s;
}stack<int> qq;
inline void tarjan(int x){
dfn[x]=++cnt;low[x]=cnt;stackf[x]=1;qq.push(x);
for (int i=h1[x];i;i=data1[i].next){
int y=data1[i].y;
if (!dfn[y]) tarjan(y),low[x]=min(low[y],low[x]);else if(stackf[y]) low[x]=min(low[x],dfn[y]);
}
if (low[x]==dfn[x]){
s++;int y;
do{
y=qq.top();stackf[y]=0;qq.pop();b[y]=s;
}while(y!=x);
}
}
int main(){
freopen("cia.in","r",stdin);
t=read();
while(t--){
n=read();m=read();memset(mp,0,sizeof(mp));T=n*2+1;num=0;memset(h1,0,sizeof(h1));memset(dfn,0,sizeof(dfn));cnt=0;s=0;
for (int i=1;i<=m;++i){
int x=read(),y=read();data1[++num].y=y;data1[num].next=h1[x];h1[x]=num;
}
for (int i=1;i<=n;++i) if (!dfn[i]) tarjan(i);memset(h,0,sizeof(h));num=1;
//for (int i=1;i<=n;++i) printf("%d ",b[i]);printf("\n");
for (int i=1;i<=n;++i){
for (int j=h1[i];j;j=data1[j].next){
int y=data1[j].y;
if(b[i]!=b[y]) mp[b[i]][b[y]]=1;
}
}//printf("%d\n",s);
for (int k=1;k<=s;++k)
for (int i=1;i<=s;++i)
for (int j=1;j<=s;++j)
mp[i][j]|=mp[i][k]&mp[k][j];
//for (int i=1;i<=n;++i) printf("%d %d\n",i,mp[3][i]);
for (int i=1;i<=s;++i){
insert1(0,i,1);
for (int j=1;j<=s;++j) if (i!=j&&mp[i][j]) insert1(i,j+s,1);
insert1(i+s,T,1);
}int ans=0;
while(bfs()) ans+=dfs(0,inf);
printf("%d\n",s-ans);
}
return 0;
}