这道题其实就是网络流,难在建图。
应该可以看出,这道题就是求一个最小割。
超级源点和超级汇点这个不在赘述,主要的一个就是要把所有点都拆成流入点和流出点,并且权值设为1。
而对于与超级源点相连的点,则再加一条流量为正无穷的边,不然在用dinic算法算的时候会直接选择把这几个点切断。
#include<cstdio>
#include<cstring>
const int MAXP=3000*2;
const int MAXC=20000;
const int MAX=(MAXC*3+MAXP*3+10)*2;
const int INF=30000;
int p,c,n;
int s,t,k,first[MAXP+3],next[MAX],head[MAX],tail[MAX],f[MAX];
int q[MAXP+3],qhead,qtail;
int d[MAXP+3];
int ans;
inline void open_file(void)
{
freopen("damage2.in","r",stdin);
freopen("damage2.out","w",stdout);
}
inline int getint(void)
{
int a;
scanf("%d",&a);
return a;
}
inline void addedge(int u,int v,int w,int k)
{
next[k]=first[u];
first[u]=k;
head[k]=u;
tail[k]=v;
f[k]=w;
}
inline void init(void)
{
p=getint();
c=getint();
n=getint();
s=p+p+1;
t=1;
k+=2;
addedge(1,1+p,INF,k);
addedge(1+p,1,INF,k^1);
for(int i=2;i<=p;i++)
{
k+=2;
addedge(i,i+p,1,k);
addedge(i+p,i,0,k^1);
}
for(int i=1;i<=c;i++)
{
int a,b;
a=getint();
b=getint();
if(a==b)
continue;
k+=2;
addedge(a+p,b,INF,k);
addedge(b,a+p,0,k^1);
k+=2;
addedge(b+p,a,INF,k);
addedge(a,b+p,0,k^1);
}
for(int i=1;i<=n;i++)
{
int r=getint();
k+=2;
addedge(s,r,INF,k);
addedge(r,s,0,k^1);
k+=2;
addedge(r,r+p,INF,k);
addedge(r+p,r,INF,k^1);
}
}
inline bool bfs(void)
{
qhead=0;
qtail=0;
memset(d,0,sizeof(d));
d[t]=1;
q[qtail++]=t;
while(qhead<qtail)
{
int u=q[qhead++];
for(int e=first[u];e;e=next[e])
{
int v=tail[e];
if(!d[v]&&f[e^1])
{
q[qtail++]=v;
d[v]=d[u]+1;
}
}
}
return d[s];
}
int dfs(int u,int b)
{
if(u==t)
return b;
int r=0,tmp=0;
for(int e=first[u];e;e=next[e])
{
int v=tail[e];
if(d[v]<d[u]&&f[e])
{
tmp=dfs(v,(b-r)<f[e]?(b-r):f[e]);
f[e]-=tmp;
f[e^1]+=tmp;
r+=tmp;
}
}
return r;
}
inline void solve(void)
{
while(bfs())
{
ans+=dfs(s,INF);
}
}
inline void output(void)
{
printf("%d\n",ans);
}
inline void close_file(void)
{
fclose(stdin);
fclose(stdout);
}
int main()
{
open_file();
init();
solve();
output();
close_file();
return 0;
}