题目传送门
题面有点坑(对于我这种不读题面的人来说)
题面上有个大大的图。我看了一下好像是环诶。
我就以为这题有环。
一开始
我想:
既然有环,那么我用强联通缩点之后每个环最多只能选出一个点咯。
然后我再在剩下的点里面求点集,使两两不能互相到达。
然后我看错了:
题目说显然,水系中不会有环流(下图描述一个环流的例子)
微笑。
然而这道题是裸的最大独立集。
学(mo)了一发。
师兄blog
最大独立集=点数-最大匹配。
代码实现:(有强联通版本。。)
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
struct node {
int x,y,next;
}a[1100];int len,last[110];
void ins(int x,int y) {
len++;
a[len].x=x;a[len].y=y;
a[len].next=last[x];last[x]=len;
}
int belong[110],sta[1100],tp,cnt;
int low[110],dfn[110],id;
bool v[110];
void dfs(int x) {
low[x]=dfn[x]=++id;
sta[++tp]=x;v[x]=true;
for(int k=last[x];k;k=a[k].next) {
int y=a[k].y;
if(dfn[y]==-1) {
dfs(y);
low[x]=min(low[x],low[y]);
}
else
if(v[y]==true)
low[x]=min(low[x],dfn[y]);
}
if(dfn[x]==low[x]) {
int i;cnt++;
do {
i=sta[tp--];
belong[i]=cnt;
v[i]=false;
}while(i!=x);
}
}
int map[110][110],match[110];
bool chw[110];
bool get_match(int x) {
for(int i=1;i<=cnt;i++)
if(map[x][i]==true)
if(chw[i]==false) {
chw[i]=true;
if(match[i]==0||get_match(match[i])==true) {
match[i]=x;return true;
}
}
return false;
}
int main() {
int n,m;scanf("%d%d",&n,&m);
len=0;memset(last,0,sizeof(last));
for(int i=1;i<=m;i++) {
int x,y;scanf("%d%d",&x,&y);
ins(x,y);
}
memset(dfn,-1,sizeof(dfn));
memset(sta,0,sizeof(sta));
memset(v,false,sizeof(v));
memset(low,0,sizeof(low));
tp=id=cnt=0;
for(int i=1;i<=n;i++)
if(dfn[i]==-1)
dfs(i);
memset(map,false,sizeof(map));
for(int i=1;i<=len;i++)
if(belong[a[i].x]!=belong[a[i].y])
map[belong[a[i].x]][belong[a[i].y]]=true;
for(int k=1;k<=cnt;k++)
for(int i=1;i<=cnt;i++)
for(int j=1;j<=cnt;j++)
if(map[i][k]==true&&map[k][j]==true)
map[i][j]=true; //要加floyd使得间接连通也算联通
int ans=0;memset(match,0,sizeof(match));
for(int i=1;i<=cnt;i++) {
memset(chw,false,sizeof(chw));
if(get_match(i)==true)
ans++;
}
printf("%d\n",cnt-ans);
return 0;
}
不加强联通:
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
int map[110][110],match[110];
bool chw[110];int n;
bool get_match(int x) {
for(int i=1;i<=n;i++)
if(map[x][i]==true)
if(chw[i]==false) {
chw[i]=true;
if(match[i]==0||get_match(match[i])==true) {
match[i]=x;return true;
}
}
return false;
}
int main() {
int m;scanf("%d%d",&n,&m);
memset(map,false,sizeof(map));
for(int i=1;i<=m;i++) {
int x,y;scanf("%d%d",&x,&y);
map[x][y]=true;
}
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(map[i][k]==true&&map[k][j]==true)
map[i][j]=true;
int ans=0;
memset(match,0,sizeof(match));
for(int i=1;i<=n;i++) {
memset(chw,false,sizeof(chw));
if(get_match(i)==true)
ans++;
}
printf("%d\n",n-ans);
return 0;
}