目录
显示
题目链接
https://www.luogu.com.cn/problem/P4589
题解
显然要用到二分答案,问题在于如何判定一个答案是否能达到呢?
题目的本质是用 \(n+1\) 条链覆盖图上的点,目标是让没被覆盖的点中最小权值最大化。
我们考虑建立网络流的模型。设我们的目标是覆盖权值前 \(mid\) 小的点。
首先建立超级源和超级汇 \(ss,tt\),连接 \(ss \to s\) 和 \(t \to tt\),流量为 \(n+1\),费用 \(0\)(代表 \(n+1\) 条链)。
接下来将每个点拆成入点和出点两个点,从 \(s\) 向所有入点,所有出点向 \(t\) 连流量为 \(\infty\),费用 \(0\) 的边。
对于原有的边 \(x \to y\),从 \(x\) 的出点向 \(y\) 的入点连流量 \(\infty\),费用 \(0\) 的边。
对于每个点 \(i\),从其入点向出点连两条边:一条流量,费用均为 \(1\)(如果权值不是前 \(mid\) 小则不连,以免影响答案判定),另一条流量为 \(\infty\),费用为 \(0\)(多次经过同一个点不影响结果)。
跑最大费用最大流即可,费用即为覆盖到的点数。
#include <cstring> #include <iostream> #include <vector> #include <queue> #include <algorithm> #define INF 0x3f3f3f3f using namespace std; struct node { int id,v; }p[505]; vector<int> e[505]; int n,m; struct graph { struct edge { int v,w,c,next; }e[1000005]; struct node { int v,e; }p[2005]; int head[2005],dis[2005],vis[2005]; int s,t,cnt,minc; void init(int S,int T) { memset(head,0,sizeof(head)); cnt=1,minc=0; s=S,t=T; } void addedge(int u,int v,int w,int c) { e[++cnt].v=v; e[cnt].w=w; e[cnt].c=c; e[cnt].next=head[u]; head[u]=cnt; } bool spfa() { queue<int> q; memset(dis,INF,sizeof(dis)); dis[s]=0,vis[s]=1; q.push(s); while(!q.empty()) { int u=q.front(); q.pop(); vis[u]=0; for(int i=head[u];i;i=e[i].next) if(e[i].w&&dis[u]-e[i].c<dis[e[i].v]) { dis[e[i].v]=dis[u]-e[i].c; p[e[i].v].v=u; p[e[i].v].e=i; if(!vis[e[i].v]) { vis[e[i].v]=1; q.push(e[i].v); } } } return dis[t]!=INF; } int mcmf() { while(spfa()) { int minw=INF; for(int i=t;i!=s;i=p[i].v) minw=min(minw,e[p[i].e].w); for(int i=t;i!=s;i=p[i].v) { e[p[i].e].w-=minw; e[p[i].e^1].w+=minw; } minc+=minw*dis[t]; } return -minc; } }g; bool cmp(const node&a,const node&b) { return a.v<b.v; } bool check(int x) { int maxv=p[x].v; int s=2*m+1,t=2*m+2; g.init(s,t); g.addedge(s,s+2,n,0),g.addedge(s+2,s,0,0); g.addedge(t+2,t,n,0),g.addedge(t,t+2,0,0); for(int i=1;i<=m;i++) { int u=p[i].id; g.addedge(s+2,u,INF,0),g.addedge(u,s+2,0,0); g.addedge(u+m,t+2,INF,0),g.addedge(t+2,u+m,0,0); if(p[i].v<=maxv) g.addedge(u,u+m,1,1),g.addedge(u+m,u,0,-1); g.addedge(u,u+m,INF,0),g.addedge(u+m,u,0,0); for(auto v:e[u]) g.addedge(u+m,v,INF,0),g.addedge(v,u+m,0,0); } return g.mcmf()>=x; } int main() { cin>>n>>m; n++; for(int i=1;i<=m;i++) { int k; cin>>p[i].v>>k; p[i].id=i; while(k--) { int x; cin>>x; e[i].push_back(x); } } sort(p+1,p+m+1,cmp); int l=1,r=m,ans=0; while(l<=r) { int mid=(l+r)>>1; if(check(mid))ans=mid,l=mid+1; else r=mid-1; } if(ans==m)cout<<"AK"<<endl; else cout<<p[ans+1].v<<endl; return 0; }