Time Limit: 10000/4000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 771 Accepted Submission(s): 236
这题和HDU3081 很类似。
但是因为可以随意选择K个人。
所以要将女孩拆成两个点。
将每个女孩u分为u1,u2,若u喜欢v则加一条u1到v的边 否则加一条u2到v的边,令加u1到u2的容量为k的边;
这个拆点的想法非常巧妙。
//============================================================================ // Name : HDU.cpp // Author : // Version : // Copyright : Your copyright notice // Description : Hello World in C++, Ansi-style //============================================================================ #include <iostream> #include <stdio.h> #include <string.h> #include <algorithm> using namespace std; const int MAXN=1000; int maze[MAXN][MAXN]; int gap[MAXN],dis[MAXN],pre[MAXN],cur[MAXN]; int flow[MAXN][MAXN]; int sap(int start,int end,int nodenum) { memset(cur,0,sizeof(cur)); memset(dis,0,sizeof(dis)); memset(gap,0,sizeof(gap)); memset(flow,0,sizeof(flow)); int u=pre[start]=start,maxflow=0,aug=-1; gap[0]=nodenum; while(dis[start]<nodenum) { loop: for(int v=cur[u];v<nodenum;v++) if(maze[u][v]-flow[u][v] && dis[u]==dis[v]+1) { if(aug==-1||aug>maze[u][v]-flow[u][v])aug=maze[u][v]-flow[u][v]; pre[v]=u; u=cur[u]=v; if(v==end) { maxflow+=aug; for(u=pre[u];v!=start;v=u,u=pre[u]) { flow[u][v]+=aug; flow[v][u]-=aug; } aug=-1; } goto loop; } int mindis=nodenum-1; for(int v=0;v<nodenum;v++) if(maze[u][v]-flow[u][v]&&mindis>dis[v]) { cur[u]=v; mindis=dis[v]; } if((--gap[dis[u]])==0)break; gap[dis[u]=mindis+1]++; u=pre[u]; } return maxflow; } int F[260]; int find(int x) { if(F[x]==-1)return x; else return F[x]=find(F[x]); } void bing(int x,int y) { int t1=find(x); int t2=find(y); if(t1!=t2)F[t1]=t2; } int n,m,f; int K; int a[250*250],b[250*250]; bool check(int t) { for(int i=1;i<=n;i++) maze[0][i]=t; for(int i=2*n+1;i<=3*n;i++) maze[i][3*n+1]=t; if(sap(0,3*n+1,3*n+2)==t*n)return true; else return false; } void solve() { memset(maze,0,sizeof(maze)); for(int i=0;i<m;i++) for(int j=1;j<=n;j++) { if(find(j)==find(a[i]) && maze[j][b[i]+2*n]==0) { maze[j][b[i]+2*n]=1; } } /* * 将每个女孩u分为u1,u2,若u喜欢v则加一条u1到v的边 否则加一条u2到v的边,令加u1到u2的容量为k的边; */ for(int i=1;i<=n;i++) { for(int j=2*n+1;j<=3*n;j++) { if(maze[i][j]==0) maze[n+i][j]=1; } maze[i][n+i]=K; } int l=0,r=n; int ans=0; while(l<=r) { int mid=(l+r)/2; if(check(mid)) { ans=mid; l=mid+1; } else r=mid-1; } printf("%d\n",ans); } int main() { // freopen("in.txt","r",stdin); // freopen("out.txt","w",stdout); int T; scanf("%d",&T); while(T--) { scanf("%d%d%d%d",&n,&m,&K,&f); memset(F,-1,sizeof(F)); for(int i=0;i<m;i++) scanf("%d%d",&a[i],&b[i]); int u,v; while(f--) { scanf("%d%d",&u,&v); bing(u,v); } solve(); } return 0; }