题目传送门

题意:

  有n个人,m对关系,要求每对关系中,有且仅有一个人给另外一个人送礼物,并且使送出礼物最多的人送的礼物尽可能少。并输出送礼物的方案。

思路:这道题麻烦的是网络流模型的转换(废话)。

  最关键的因素是每对关系中只有一个人能给另外一个人送礼物,也就是说是不能相互送礼物的,虽然这句话是废话,但是正因为如此,如果我们考虑直接按照人建点,最后的方案会有问题。(流量相同,但方案错误)。

#pragma GCC optimize (2)
#pragma G++ optimize (2)
#pragma comment(linker, "/STACK:102400000,102400000")
#include<bits/stdc++.h>
#include<cstdio>
#include<vector>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define dep(i,b,a) for(int i=b;i>=a;i--)
#define clr(a,b) memset(a,b,sizeof(a))
#define pb push_back
#define pii pair<int,int >
using namespace std;
typedef long long ll;
const int maxn=;
const int inf=0x3f3f3f3f;
ll rd()
{
ll x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
}
const ll INFLL = 0x3f3f3f3f3f3f3f3f;
const int INF = 0x3f3f3f3f; struct Edge {
int to, flow, nxt;
Edge() {}
Edge(int to, int nxt, int flow):to(to),nxt(nxt), flow(flow) {}
} edge[maxn << ]; int head[maxn], dep[maxn];
int S, T;
int N, n, m, tot,cnt;
vector<pair<int,int> >va;
void Init(int n) {
N = n;
for (int i = ; i <= N; ++i) head[i] = -;
tot = ;
} void addv(int u, int v, int w, int rw = ) {
edge[tot] = Edge(v, head[u], w);
head[u] = tot++;
edge[tot] = Edge(u, head[v], rw);
head[v] = tot++;
} bool BFS() {
for (int i = ; i <= N; ++i) dep[i] = -;
queue<int>q;
q.push(S);
dep[S] = ;
while (!q.empty()) {
int u = q.front();
q.pop();
for (int i = head[u]; ~i; i = edge[i].nxt) {
if (edge[i].flow && dep[edge[i].to] == -) {
dep[edge[i].to] = dep[u] + ;
q.push(edge[i].to);
}
}
}
return dep[T] < ? : ;
} int DFS(int u, int f) {
if (u == T || f == ) return f;
int w, used = ;
for (int i = head[u]; ~i; i = edge[i].nxt) {
if (edge[i].flow && dep[edge[i].to] == dep[u] + ) {
w = DFS(edge[i].to, min(f - used, edge[i].flow));
edge[i].flow -= w;
edge[i ^ ].flow += w;
used += w;
if (used == f) return f;
}
}
if (!used) dep[u] = -;
return used;
} int Dicnic() {
int ans = ;
while (BFS()) {
ans += DFS(S, INF);
}
return ans;
}
int vs[][];
bool check(int res){
Init(T);
rep(i,,m){
addv(i+n,T,);
}
rep(i,,n){
addv(S,i,res);
}
rep(i,,m-){
int u=va[i].first,v=va[i].second;
addv(u,i++n,);
addv(v,i++n,);
}
int flow=Dicnic();
if(flow>=m){
return true;
}
return false;
} int main() {
while (~scanf("%d %d", &n, &m)) {
va.clear();
S = , T = n+m+;
rep(i,,m){
int u,v;
scanf("%d%d",&u,&v);
va.push_back({u,v});
}
int l=,r=n+,mid,ans=-;
while(l<=r){
mid=(l+r)>>;
if(check(mid)){
ans=mid;
r=mid-;
}else{
l=mid+;
}
} check(ans);
printf("%d\n", ans);
int flow=Dicnic();
for(int u=;u<=n;u++){
for(int i=head[u];i!=-;i=edge[i].nxt){ if(edge[i].flow==&&edge[i].to>n){
int id=edge[i].to-n;
int x= (va[id-].first==u?va[id-].second:va[id-].first);
printf("%d %d\n",u,x);
}
}
}
}
}

  所以我们要考虑建立n个点,每个点对应一个人,再建立m个点,每个点对应一对关系,每个关系向汇点连一条容量为1的边,每个人向自己所处的所有关系都连容量为1的边,这样就使得上面说的这个条件成立了。然后我们就建立虚拟源点,二分每个源点向人的流量,每次重新建图即可。

  最后输出方案,每个点流出的容量为0的边就是方案。

最新文章

  1. 利用box-shadow实现伪边框透明到图片
  2. How to take partial screenshot with Selenium WebDriver in python
  3. [zt]OpenCV2.1.0的安装
  4. Diameter消息应用层路由
  5. 使用git客户端获取shiro
  6. python SendMail 发送邮件
  7. Codeforces Round #Pi (Div. 2) A. Lineland Mail 水题
  8. jquery 请求jsp传递json数据的方法
  9. Unity3d Shader开发(三)Pass(Pass Tags,Name,BindChannels )
  10. 去掉标题栏的方法(使用requestWindowFeature(Window.FEATURE_NO_TITLE);为什么失效)
  11. Yii框架中使用mongodb扩展
  12. Dubbo+zookeeper构建高可用分布式集群(二)-集群部署
  13. 【vue】vue +element 搭建项目,Qs用途
  14. JDK 1.8源码阅读 TreeMap
  15. 201621123018《java程序设计》第14周作业总结
  16. Invalid file name: must contain only [a-z0-9_.]【Android报错】
  17. BugPhobia开发篇章:Beta阶段第II次Scrum Meeting
  18. JMeter:生成漂亮的多维度的HTML报告
  19. 捕获长时间不提交的SQL语句
  20. 封装一个音乐列表music-list基础组件,可以共用,哪个需要的时候就是哪个props相应的值

热门文章

  1. java 方法的定义与调用
  2. 【串线篇】依赖注入DI与控制反转IOC
  3. CNN基础四:监测并控制训练过程的法宝——Keras回调函数和TensorBoard
  4. java输出当前文件所在路径
  5. bzoj 2013
  6. POJ A Plug for UNIX (最大流 建图)
  7. 【Flutter学习】之动画实现原理浅析(一)
  8. (转)Spring Boot干货系列:(三)启动原理解析
  9. python 国内镜像加速
  10. 建站手册-浏览器信息:Netscape 浏览器