题意:题意和3081一样就是多了一个条件:每一个女生可以另外强制选择K的男生经行交往,不管他们是否吵架,不管男生是否愿意。
想法:大体见图还是和之前的3081一样的。但是这里多了一个条件,那应该怎么办呢?
多的这个条件表示女生有了更多的选择,那么就要体现在图中,EX:对于标号为x的女生来说,如果直接把这个女生向所有有争吵的男生连一条边,显然这样的连边是不能限制,他最多可连接K个人。可以把x的拆成x,x'点,x->x'连一条容量为K的边,再让k'想所有有争吵的男生连一条容量为1的边就好了。这个要提前处理,不然会超时。
#include<iostream> #include<cstring> #include<cstdio> #include<queue> #define inf 0x7fffffff using namespace std; const int nodes=900; const int edges=300000; int n,m,f,s,t,K; int father[nodes]; int vis[nodes][nodes]; struct node { int v,next; int flow; }e[edges]; struct nodee { int a,b; }person[edges]; int head[nodes],cur[nodes],cnt,ff[nodes]; void Init() { memset(head,-1,sizeof(head)); cnt=0; } class Dinic { public: int spath() { queue<int>q; while(!q.empty()) q.pop(); memset(dis,-1,sizeof(dis)); dis[s]=0; q.push(s); while(!q.empty()) { int u=q.front(); q.pop(); for(int i=head[u];i+1;i=e[i].next) { int v=e[i].v; if(dis[v]==-1&&e[i].flow>0) { dis[v]=dis[u]+1; q.push(v); } } } return dis[t]!=-1; } int Min(int a,int b) { if(a<b) return a; return b; } int dfs(int u,int flow) { int cost=0; if(u==t) return flow; for(int &i=cur[u];i+1;i=e[i].next) { int v=e[i].v; if(dis[v]==dis[u]+1&&e[i].flow>0) { int min=dfs(v,Min(e[i].flow,flow-cost)); if(min>0) { e[i].flow-=min; e[i^1].flow+=min; cost+=min; if(cost==flow) break; } else dis[v]=-1; } } return cost; } int result() { int res=0; while(spath()) { for(int i=s;i<=t;i++) cur[i]=head[i]; res+=dfs(s,inf); } return res; } private: int dis[nodes]; }dinic; class UF { public: void Init() { for(int i=1;i<=260;i++) { father[i]=i; rank[i]=1; } } int find_set(int x) { if(x!=father[x]) father[x]=find_set(father[x]); return father[x]; } void union_set(int a,int b) { a=find_set(a); b=find_set(b); if(a==b) return; if(rank[a]>rank[b]) { rank[a]+=rank[b]; father[b]=a; } else { rank[b]+=rank[a]; father[a]=b; } } private: int rank[nodes]; }uf; void add(int a,int b,int c) { e[cnt].v=b; e[cnt].flow=c; e[cnt].next=head[a]; head[a]=cnt++; e[cnt].v=a; e[cnt].flow=0; e[cnt].next=head[b]; head[b]=cnt++; } void Input() { scanf("%d%d%d%d",&n,&m,&K,&f); for(int i=0;i<m;i++) { scanf("%d%d",&person[i].a,&person[i].b); } for(int i=1;i<=f;i++) { int a,b; scanf("%d%d",&a,&b); uf.union_set(a,b); } for(int i=1;i<=n;i++) { ff[i]=uf.find_set(i); } memset(vis,0,sizeof(vis)); for(int i=0;i<m;i++) { int a=person[i].a; int b=person[i].b; for(int j=1;j<=n;j++) { if(ff[j]==ff[a]&&!vis[j][b]) { vis[j][b]=1; } } } } void build_map(int k) { s=0;t=3*n+1; Init(); for(int i=1;i<=n;i++) { add(s,i,k); add(i,i+2*n,K); add(i+n,t,k); } for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { if(!vis[i][j]) add(i+2*n,j+n,1); else add(i,j+n,1); } } } void treatment() { int lft=0,rht=n; int max=0; while(lft<=rht) { int mid=(rht+lft)/2; build_map(mid); int k=dinic.result(); if(k==mid*n) { max=mid; lft=mid+1; } else { rht=mid-1; } } printf("%d\n",max); } int main() { int t; scanf("%d",&t); while(t--) { uf.Init(); Input(); treatment(); } return 0; }