【bzoj2893】征服王
比较明显的缩点,变成dag上最小路径覆盖,指定了起点终点所以建模有一些变化。
跑费用流,增广的次数即为答案。
#include<bits/stdc++.h> #define maxn 5005 #define maxm 100005 #define INF 0x7f7f7f7f using namespace std; inline int read(){ int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } struct scsc{ int next,from,to,w,c; }edge[maxm<<1]; struct _scsc{ int next,to; }_edge[maxm<<1]; int n,m,_Len,Len,scc,top,Time,_head[maxn],head[maxn],dfn[maxn],low[maxn],s[maxn],vis[maxn],hav[maxn],belong[maxn],p[maxn][2]; int sss,ttt,ss[maxn],tt[maxn],d[maxn],pre[maxn]; void addedge(int u,int v,int w,int c){ edge[++Len].to=v;edge[Len].from=u;edge[Len].next=head[u];edge[Len].w=w;edge[Len].c=c;head[u]=Len; edge[++Len].to=u;edge[Len].from=v;edge[Len].next=head[v];edge[Len].w=0;edge[Len].c=-c;head[v]=Len; } void _addedge(int u,int v){ _edge[++_Len].to=v;_edge[_Len].next=_head[u];_head[u]=_Len; } void tarjan(int u){ dfn[u]=low[u]=++Time; s[++top]=u;vis[u]=1; for(int i=_head[u];i;i=_edge[i].next){ int v=_edge[i].to; if(!dfn[v]){ tarjan(v); low[u]=min(low[u],low[v]); }else if(vis[v])low[u]=min(low[u],dfn[v]); } int now=0; if(dfn[u]==low[u]){ ++scc; while(now!=u){ now=s[top--]; vis[now]=0; ++hav[scc]; belong[now]=scc; } } } int id=0; void rebuild(int s,int t){ for(int i=1;i<=scc;++i)p[i][0]=++id,p[i][1]=++id; for(int i=1;i<=sss;++i)addedge(s,p[belong[ss[i]]][0],INF,0); for(int i=1;i<=ttt;++i)addedge(p[belong[tt[i]]][1],t,INF,0); for(int i=1;i<=scc;++i)addedge(p[i][0],p[i][1],1,1),addedge(p[i][0],p[i][1],INF,0); for(int u=1;u<=n;++u){ for(int i=_head[u];i;i=_edge[i].next){ int v=_edge[i].to; if(belong[u]!=belong[v]) addedge(p[belong[u]][1],p[belong[v]][0],INF,0); } } } int spfa(int s,int t){ queue<int>Q; memset(d,-1,sizeof(d)); Q.push(s);vis[s]=1;d[s]=0; while(!Q.empty()){ int u=Q.front();Q.pop(); for(int i=head[u];i;i=edge[i].next){ int v=edge[i].to; if(edge[i].w&&d[v]<d[u]+edge[i].c){ d[v]=d[u]+edge[i].c;pre[v]=i; if(!vis[v]){ vis[v]=1; Q.push(v); } } } vis[u]=0; } return d[t]!=-1; } int mcmf(int s,int t){ int ret=0,now=0,last=0; while(spfa(s,t)){ int w=INF;last=now; for(int i=pre[t];i;i=pre[edge[i].from])w=min(w,edge[i].w); for(int i=pre[t];i;i=pre[edge[i].from]){ edge[i].w-=w; edge[i^1].w+=w; now+=w*edge[i].c; } if(now==last)break; ++ret; } if(now!=scc)return -1; return ret; } void Init(){ Len=1;memset(head,0,sizeof(head));id=scc=0; _Len=0;memset(_head,0,sizeof(_head)); memset(pre,0,sizeof(pre)); memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); int f1,f2; n=read();m=read();sss=read();ttt=read(); for(int i=1;i<=sss;++i)ss[i]=read(); for(int i=1;i<=ttt;++i)tt[i]=read(); for(int i=1;i<=m;++i){ f1=read();f2=read(); _addedge(f1,f2); } } void WoRk(){ for(int i=1;i<=n;++i)if(!dfn[i])tarjan(i); int s=0,t=2*n+1; rebuild(s,t); int ans=mcmf(s,t); if(ans==-1)printf("no solution\n");else printf("%d\n",ans); } int main(){ int t=read(); while(t--){ Init(); WoRk(); } return 0; }