HUST1024二分答案+最大流

来源:互联网 发布:网络域名及其管理 编辑:程序博客网 时间:2024/05/20 06:25

HUST1024 dance party

题意:N个男孩和N个女孩要开个跳舞party,把愿意一块跳舞的男孩女孩的编号给出,男孩女孩最多和K个不喜欢的女孩男孩跳舞,问最多举行几轮(每一轮的舞伴不同)

解析:拆点,二分答案—建图:源点到男孩1的边容量为二分的值,女孩1到汇点的边容量为二分的值,男孩1到喜欢女孩1的边容量为1,男孩1到男孩2的边容量为k,男孩2到不喜欢女孩2的边容量为1,女孩2到女孩1的边容量为k,求最大流
#include <cstdio>#include <cstring>#define INF 0x3f3f3f3f#define max(a,b) (a) > (b) ? (a) : (b)#define min(a,b) (a) < (b) ? (a) : (b)using namespace std;const int MAXN = 500;struct Edge{int v,cap,next;Edge(){}Edge(int _v,int _cap,int _next):v(_v),cap(_cap),next(_next){}}edge[2*MAXN*MAXN];int n,m;int head[MAXN],size;int h[MAXN],agree[MAXN][MAXN];int N,M,K,src,sink;inline void init(){size = 0;memset(head,-1,sizeof(head));}inline void add_edge(int u,int v,int x){edge[size] = Edge(v,x,head[u]);head[u] = size++;edge[size] = Edge(u,0,head[v]);head[v] = size ++;}inline int BFS(){int tou,tail;int u,v,w,tep;int que[MAXN];memset(h,-1,sizeof(h));h[src] = 0;tou = tail = 0;que[tail++] = src;while (tail > tou){u = que[tou++];for(int i = head[u]; i != -1; i = edge[i].next){v = edge[i].v;w = edge[i].cap;if (h[v] == -1 && w > 0){h[v] = h[u] + 1;que[tail++] = v;}}}return h[sink] != -1;}inline int DFS(int u,int flow){if(u == sink)return flow;int i,tmpf,minf,v,w;tmpf = 0;for(i = head[u]; i != -1; i = edge[i].next){v = edge[i].v;w = edge[i].cap;if(h[v] == h[u] + 1 && w > 0 && tmpf < flow && (minf = DFS(v,min(w,flow-tmpf)))){edge[i].cap -= minf;if(i%2 == 0)edge[i+1].cap += minf;else edge[i-1].cap += minf;tmpf += minf;}}if(tmpf == 0)h[u] = -1;return tmpf;}inline int dinic(){int t,ans = 0;while (BFS()){while (t = DFS(src,INF))ans += t;}return ans;}inline bool check(int mid){init();for(int i = 1; i <= n; ++i)add_edge(src,i,mid);for(int i = 1; i <= n; ++i)add_edge(3*n+i,sink,mid);for(int i = 1; i <= n; ++i)add_edge(i,n+i,K);for(int i = 1; i <= n; ++i)add_edge(i+2*n,i+3*n,K);for(int i = 1; i <= n; ++i)for(int j = 1; j <= n; ++j){if(agree[i][j]){add_edge(i,3*n+j,1);}elseadd_edge(i+n,2*n+j,1);}if(dinic() >= n*mid){return true;}else return false;}inline int solve(){int high = n,low = 0;int mid;while (low <= high){mid = (low+high)/2;if(check(mid))low = mid + 1;else high = mid - 1;}return high;}int main(){int cas;scanf("%d",&cas);while (cas --){scanf("%d%d%d",&n,&m,&K);int a,b,c;src = 0;sink = 4*n + 1;N = 4*n + 2;memset(agree,0,sizeof(agree));while (m --){scanf("%d%d",&a,&b);agree[a][b]  = 1;}int ans = solve();printf("%d\n",ans);}return 0;}


原创粉丝点击