您的位置:首页 > 其它

【GDKOI2017模拟1.21】Book

2017-01-21 19:46 309 查看

Description

曾经有一枚珍稀的邮票摆在我的面前,

我没有好好珍惜 等到失去时 才感到后悔。

——小Z

小Z曾经是集邮部的成员,集邮部经常举办换邮票活动。活动中,如果两个人互相喜欢对方的邮票,那么这两个人就可以彼此交换自己的邮票。但在这个规则下,小Z没有换到自己喜欢的邮票。小Z觉得这是规则不完善导致的,于是小Z决定制定一个新的交换规则:每次可以选择任意多个人排成一个圆圈,如果每个人都喜欢他前边的人当前拥有的那枚邮票,就可以让每个人都拿走自己前边的人的邮票,并把自己的邮票给后边的人。在活动中可以进行任意多次这样的交换,并且一个人也可以多次参与这样的交换。

现在小Z知道了参加活动的人数,以及每个人喜欢哪些邮票,他想知道这次能不能让每个人都拿到一枚自己喜欢的邮票。你能帮他解决这个问题吗?

Solution

这题画画图就知道,每个人喜欢的重点不是人,而是邮票。

所以这个邮票最后要流到这个人身上才可以,那么很显然是二分图匹配,直接根据输入数据构造二分图就好了。

由于习惯,直接上dinic

Code

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define rep(i,a) for(i=first[a];i;i=next[i])
using namespace std;
const int maxn=1e5+7;
int i,j,k,l,t,n,m,ans,S,T,op;
int first[maxn],next[maxn],last[maxn],num,chang[maxn],fan[maxn];
int d[maxn],bz[maxn],data[maxn];
bool az[maxn];
void add(int x,int y,int z){
last[++num]=y,next[num]=first[x],first[x]=num,chang[num]=z;fan[num]=num+1;
last[++num]=x,next[num]=first[y],first[y]=num,chang[num]=0;fan[num]=num-1;
}
bool bfs(){
int i,j,k,x;
i=0;j=1;memset(d,0,sizeof(d));d[S]=1;data[1]=S;
while(i<j){
x=data[++i];
rep(k,x){
if(!d[last[k]]&&chang[k]>0){
d[last[k]]=d[x]+1;
data[++j]=last[k];
}
}
}
return(d[T]!=0);
}
int dinic(int x,int y){
int i,j,t,p=0;
if(x==T){
return y;
}
rep(i,x){
if(chang[i]&&d[last[i]]==d[x]+1){
t=dinic(last[i],min(y,chang[i]));
if(t){
chang[i]-=t;
chang[fan[i]]+=t;
y-=t;p+=t;if(!y)break;
}
}
}
if(!p)d[x]=-1;
return p;
}
int main(){
freopen("book.in","r",stdin);
freopen("book.out","w",stdout);
while(scanf("%d",&n)!=EOF){
scanf("%d",&m);
memset(first,0,sizeof(first));num=0;
S=0,T=2*n+1;
fo(i,1,n)add(S,i,1),add(i+n,T,1);
fo(i,1,m){
scanf("%d%d",&k,&l);
add(k,l+n,1);
}
ans=0;
while(bfs()){
ans+=dinic(S,0x7fffffff);
}
if(ans!=n)printf("NO\n");else printf("YES\n");
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: