[bzoj 1305&1433]最大流练习题
2017-06-20 16:53
162 查看
1305: [CQOI2009]dance跳舞
Time Limit: 5 Sec Memory Limit: 162 MBSubmit: 3330 Solved: 1409
[Submit][Status][Discuss]
Description
一次舞会有n个男孩和n个女孩。每首曲子开始时,所有男孩和女孩恰好配成n对跳交谊舞。每个男孩都不会和同一个女孩跳两首(或更多)舞曲。有一些男孩女孩相互喜欢,而其他相互不喜欢(不会“单向喜欢”)。每个男孩最多只愿意和k个不喜欢的女孩跳舞,而每个女孩也最多只愿意和k个不喜欢的男孩跳舞。给出每对男孩女孩是否相互喜欢的信息,舞会最多能有几首舞曲?Input
第一行包含两个整数n和k。以下n行每行包含n个字符,其中第i行第j个字符为'Y'当且仅当男孩i和女孩j相互喜欢。Output
仅一个数,即舞曲数目的最大值。Sample Input
3 0YYY
YYY
YYY
Sample Output
3HINT
N<=50 K<=30Source
加强数据Bydwellings and liyizhen2
这两题的难点就难在建图 建图过程详见代码注释
对于dfs的写法稍有改变 如按照原模板会超时。。。
借鉴hzwer的写法
//http://www.lydsy.com/JudgeOnline/problem.php?id=1305 #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> #include<cmath> #include<queue> #define inf 0x7fffffff using namespace std; int n,k,cnt=1;int start=0,end=1001; int ans; int mp[1005][1005],head[1005],d[1005]; struct edge{int to,w,next;}e[500001]; int mid; void ini(int x,int y,int z){ e[++cnt].to=y;e[cnt].w=z;e[cnt].next=head[x];head[x]=cnt; } void insert(int x,int y,int z){ ini(x,y,z);ini(y,x,0); } queue<int>q; bool bfs(){ memset(d,-1,sizeof(d)); d[start]=0; q.push(start); while(!q.empty()){ int k=q.front();q.pop(); for(int i=head[k];i;i=e[i].next){ int kk=e[i].to; if(d[kk]==-1&&e[i].w>0){ d[kk]=d[k]+1; q.push(kk); } } } if(d[end]==-1) return false; return true; } int dfs(int x,int f) { if(x==end)return f; int w,used=0,i; i=head[x]; while(i) { if(e[i].w&&d[e[i].to]==d[x]+1) { w=f-used; w=dfs(e[i].to,min(w,e[i].w)); e[i].w-=w; e[i^1].w+=w; used+=w; if(used==f)return f; } i=e[i].next; } if(!used) d[x]=-1; return used; } int dinic(){ while(bfs()){ int a; if(a=dfs(0,inf)) ans+=a; } } void build(){ cnt=1; memset(head,0,sizeof(head)); for(int i=1;i<=n;i++) insert(start,i,mid);//超级源和男的入点连 for(int i=1;i<=n;i++) insert(i,i+500,k);//男的入点连出点 for(int i=1;i<=n;i++) insert(i+n+500,i+n,k);//女 出点连入点 for(int i=1;i<=n;i++) insert(i+n,end,mid);//女的入点和超级汇连 for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(mp[i][j]) insert(i,n+j,1);//喜欢就连入点 else insert(i+500,n+j+500,1);//否则连出点 } int main(){ //freopen("rand.txt","r",stdin); scanf("%d%d",&n,&k); char s[100]; for(int i=1;i<=n;i++) { scanf("%s",s+1); for(int j=1;j<=n;j++) { if(s[j]=='Y') mp[i][j]=1; } } int l=0,r=50; int mx=0; while(l<=r){ mid=(l+r)>>1; build(); ans=0;dinic(); if(ans>=n*mid){ mx=mid; l=mid+1; } else r=mid-1; } printf("%d",mx); return 0; }
1433: [ZJOI2009]假期的宿舍
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 2927 Solved: 1237
[Submit][Status][Discuss]
Description
Input
Output
Sample Input
13
1 1 0
0 1 0
0 1 1
1 0 0
1 0 0
Sample Output
ˆ ˆHINT
对于30% 的数据满足1 ≤ n ≤ 12。对于100% 的数据满足1 ≤ n ≤ 50,1 ≤ T ≤ 20。
Source
//http://www.lydsy.com/JudgeOnline/problem.php?id=1433 //拆点 把人和床分开 1-n是人 1+n-2*n是床 //床和汇点连 源点连要床的人 每个人和能睡的床连 #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> #include<cmath> #include<queue> #define inf 0x7fffff using namespace std; int d[105],head[105],n,cnt=1,school[105],ans,tot; int start=0,end=101; struct edge{int to,next,w;}e[50005]; void ini(int x,int y,int z){ e[++cnt].to=y;e[cnt].w=z;e[cnt].next=head[x];head[x]=cnt; } void insert(int x,int y,int z){ ini(x,y,z);ini(y,x,0); } queue<int>q; bool bfs(){ q.push(start); memset(d,-1,sizeof(d)); d[start]=0; while(!q.empty()){ int k=q.front();q.pop(); for(int i=head[k];i;i=e[i].next) { int kk=e[i].to; if(d[kk]==-1&&e[i].w>0) { d[kk]=d[k]+1; q.push(kk); } } } if(d[end]==-1) return false; return true; } int dfs(int x,int f){ if(x==end) return f; int a,used=0; for(int i=head[x];i;i=e[i].next){ int k=e[i].to; if(d[k]==d[x]+1&&e[i].w>0){ a=f-used; a=dfs(k,min(a,e[i].w)); e[i].w-=a; e[i^1].w+=a; used+=a; if(used==f) return f; } } if(!used) d[x]=-1; return used; } void dinic(){ while(bfs()) ans+=dfs(start,inf); } int main(){ int T; scanf("%d",&T); while(T--){ ans=tot=0;cnt=1;memset(head,0,sizeof(head)); scanf("%d",&n); int temp; for(int i=1;i<=n;i++) { scanf("%d",&school[i]); if(temp==1) insert(i+n,end,1);//住校代表有床 床连汇点 } int x; for(int i=1;i<=n;i++){ scanf("%d",&x); if((school[i]&&!x)||!school[i]){//源点连需要床的人 insert(start,i,1);tot++; } } for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) { scanf("%d",&x); if(x||i==j) insert(i,j+n,1);//人连能睡的床 } dinic(); if(ans==tot)puts("^_^"); else puts("T_T"); } return 0; }
相关文章推荐
- [BZOJ 1093 && YZOI1172] Tarjan缩点+拓扑DP 最大半连通子图
- [BZOJ 1012] JSOI 2008 最大数maxnumber · 线段树
- [BZOJ1433][ZJOI2009]假期的宿舍(最大流)
- 【BZOJ】1433 [ZJOI2009]假期的宿舍 二分图的最大匹配
- [二分图最大匹配] BZOJ1433: [ZJOI2009]假期的宿舍
- 最大权闭合图 && 【BZOJ】1497: [NOI2006]最大获利
- [几何 LIS] BZOJ 3663 Crazy Rabbit & 4660 Crazy Rabbit & 4206 最大团
- 【BZOJ1433】【codevs2347】假期的宿舍,最大流
- bzoj 2547: [Ctsc2002]玩具兵 bfs&最大匹配
- bzoj3663/4660CrazyRabbit && bzoj4206最大团
- poj 2711 Leapin' Lizards && BZOJ 1066: [SCOI2007]蜥蜴 最大流
- bzoj1433 [ZJOI2009]假期的宿舍(最大流)
- bzoj1093 最大半连通子图 强连通分量&记忆化搜索
- bzoj 1433: [ZJOI2009]假期的宿舍(最大流)
- [华为机试练习题]55.最大公约数 & 多个数的最大公约数
- BZOJ 1433 ZJOI2009 假期的宿舍 最大流
- BZOJ 1012 [JSOI2008] 最大数 maxnumber 题解&代码
- BZOJ-1433 假期的宿舍 最大流+基础建图
- 假期的宿舍_bzoj1433_二分图最大匹配
- bzoj 1433: [ZJOI2009]假期的宿舍 -- 最大流