BZOJ 1305 dance跳舞 二分+最大流

题目链接:

https://www.lydsy.com/JudgeOnline/problem.php?id=1305

题目大意:

一次舞会有n个男孩和n个女孩。每首曲子开始时,所有男孩和女孩恰好配成n对跳交谊舞。每个男孩都不会和同一个女孩跳两首(或更多)舞曲。有一些男孩女孩相互喜欢,而其他相互不喜欢(不会“单向喜欢”)。每个男孩最多只愿意和k个不喜欢的女孩跳舞,而每个女孩也最多只愿意和k个不喜欢的男孩跳舞。给出每对男孩女孩是否相互喜欢的信息,舞会最多能有几首舞曲?

思路:

二分答案,判断是否可行,每次二分答案时,用以下方式建图即可,判断是否满流,满流的话就是可行解。

  1 #include<bits/stdc++.h>
  2 #define IOS ios::sync_with_stdio(false);//不可再使用scanf printf
  3 #define Max(a, b) ((a) > (b) ? (a) : (b))//禁用于函数,会超时
  4 #define Min(a, b) ((a) < (b) ? (a) : (b))
  5 #define Mem(a) memset(a, 0, sizeof(a))
  6 #define Dis(x, y, x1, y1) ((x - x1) * (x - x1) + (y - y1) * (y - y1))
  7 #define MID(l, r) ((l) + ((r) - (l)) / 2)
  8 #define lson ((o)<<1)
  9 #define rson ((o)<<1|1)
 10 #define Accepted 0
 11 #pragma comment(linker, "/STACK:102400000,102400000")//栈外挂
 12 using namespace std;
 13 inline int read()
 14 {
 15     int x=0,f=1;char ch=getchar();
 16     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
 17     while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
 18     return x*f;
 19 }
 20 
 21 typedef long long ll;
 22 const int maxn = 1000 + 10;
 23 const int MOD = 1000000007;//const引用更快,宏定义也更快
 24 const int INF = 1e9 + 7;
 25 const double eps = 1e-6;
 26 struct edge
 27 {
 28     int u, v, c, f;
 29     edge(int u, int v, int c, int f):u(u), v(v), c(c), f(f){}
 30 };
 31 vector<edge>e;
 32 vector<int>G[maxn];
 33 int level[maxn];//BFS分层,表示每个点的层数
 34 int iter[maxn];//当前弧优化
 35 
 36 void init(int n)
 37 {
 38     for(int i = 0; i <= n; i++)G[i].clear();
 39     e.clear();
 40 }
 41 void addedge(int u, int v, int c)
 42 {
 43     e.push_back(edge(u, v, c, 0));
 44     e.push_back(edge(v, u, 0, 0));
 45     int m = e.size();
 46     G[u].push_back(m - 2);
 47     G[v].push_back(m - 1);
 48 }
 49 void BFS(int s)//预处理出level数组
 50 //直接BFS到每个点
 51 {
 52     memset(level, -1, sizeof(level));
 53     queue<int>q;
 54     level[s] = 0;
 55     q.push(s);
 56     while(!q.empty())
 57     {
 58         int u = q.front();
 59         q.pop();
 60         for(int v = 0; v < G[u].size(); v++)
 61         {
 62             edge& now = e[G[u][v]];
 63             if(now.c > now.f && level[now.v] < 0)
 64             {
 65                 level[now.v] = level[u] + 1;
 66                 q.push(now.v);
 67             }
 68         }
 69     }
 70 }
 71 int dfs(int u, int t, int f)//DFS寻找增广路
 72 {
 73     if(u == t)return f;//已经到达源点,返回流量f
 74     for(int &v = iter[u]; v < G[u].size(); v++)
 75         //这里用iter数组表示每个点目前的弧,这是为了防止在一次寻找增广路的时候,对一些边多次遍历
 76         //在每次找增广路的时候,数组要清空
 77     {
 78         edge &now = e[G[u][v]];
 79         if(now.c - now.f > 0 && level[u] < level[now.v])
 80             //now.c - now.f > 0表示这条路还未满
 81             //level[u] < level[now.v]表示这条路是最短路,一定到达下一层,这就是Dinic算法的思想
 82         {
 83             int d = dfs(now.v, t, min(f, now.c - now.f));
 84             if(d > 0)
 85             {
 86                 now.f += d;//正向边流量加d
 87                 e[G[u][v] ^ 1].f -= d;
 88     //反向边减d,此处在存储边的时候两条反向边可以通过^操作直接找到
 89                 return d;
 90             }
 91         }
 92     }
 93     return 0;
 94 }
 95 int Maxflow(int s, int t)
 96 {
 97     int flow = 0;
 98     for(;;)
 99     {
100         BFS(s);
101         if(level[t] < 0)return flow;//残余网络中到达不了t,增广路不存在
102         memset(iter, 0, sizeof(iter));//清空当前弧数组
103         int f;//记录增广路的可增加的流量
104         while((f = dfs(s, t, INF)) > 0)
105         {
106             flow += f;
107         }
108     }
109     return flow;
110 }
111 int n, k;
112 char Map[55][55];
113 bool judge(int m)
114 {
115     int s = 0, t = 6 * n + 1;
116     init(t);
117     for(int i = 1; i <= n; i++)
118     {
119         addedge(s, i, m);
120         addedge(i, n + i, INF);
121         addedge(i, 2 * n + i, k);
122         addedge(3 * n + i, 5 * n + i, INF);
123         addedge(4 * n + i, 5 * n + i, k);
124         addedge(5 * n + i, t, m);
125     }
126     for(int i = 1; i <= n; i++)
127     {
128         for(int j = 1; j <= n; j++)
129         {
130             if(Map[i][j] == 'Y')//互相喜欢
131                 addedge(n + i, 3 * n + j, 1);
132             else addedge(2 * n + i, 4 * n + j, 1);
133         }
134     }
135     return Maxflow(s, t) == n * m;
136 }
137 int main()
138 {
139     scanf("%d%d", &n, &k);
140     for(int i = 1; i <= n; i++)scanf("%s", Map[i] + 1);
141     int l = 0, r = n;
142     int ans = 0;
143     while(l <= r)
144     {
145         int m = (l + r) / 2;
146         if(judge(m))ans = m, l = m + 1;
147         else r = m - 1;
148     }
149     printf("%d\n", ans);
150     return Accepted;
151 }

 

posted @ 2018-09-21 19:42  _努力努力再努力x  阅读(174)  评论(0编辑  收藏  举报