bzoj 2547: [Ctsc2002]玩具兵 bfs&最大匹配
2016-04-06 18:29
330 查看
在lrj的某一本书(蓝书?紫书?黑书?我不知道>_<)里面看到过。
首先可以把交换看成是更改职业,那么二分答案x,我们就得到了每个玩具兵(不包括天兵)可以到达的目标格。那么连一条边就得到一个二分图,跑最大匹配即可。
注意不能直接判断是否有完美匹配,还要考虑天兵,因为我们可以让天兵到x个地方然后作x次交换,那么在跑最大匹配的时候不把天兵加进去,然后判断是否有最大匹配数+x>=n即可。
AC代码如下:
by lych
2016.4.6
首先可以把交换看成是更改职业,那么二分答案x,我们就得到了每个玩具兵(不包括天兵)可以到达的目标格。那么连一条边就得到一个二分图,跑最大匹配即可。
注意不能直接判断是否有完美匹配,还要考虑天兵,因为我们可以让天兵到x个地方然后作x次交换,那么在跑最大匹配的时候不把天兵加进去,然后判断是否有最大匹配数+x>=n即可。
AC代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<algorithm> #define N 115 #define M 1005 using namespace std; const int dx[4]={-1,1,0,0},dy[4]={0,0,-1,1}; int m,n,cnt,pt,tot,c ,d ,path ,mp ; struct node{ int x,y; }a ,b ,h[M+5]; bool bo ,inq ; void bfs(int sx,int sy,int p){ memset(d,0x3f,sizeof(d)); d[sx][sy]=0; int i,t,head=0,tail=1; node u,v; h[1].x=sx; h[1].y=sy; memset(inq,0,sizeof(inq)); while (head!=tail){ head=head%M+1; u=h[head]; inq[u.x][u.y]=0; for (i=0; i<4; i++){ v.x=u.x+dx[i]; v.y=u.y+dy[i]; if (v.x<=0 || v.x>m || v.y<=0 || v.y>n) continue; if (p^(d[u.x][u.y]&1)) if (c[v.x][v.y]<=c[u.x][u.y]) t=0; else t=1; else if (c[v.x][v.y]>=c[u.x][u.y]) t=0; else t=1; if (d[u.x][u.y]+t<d[v.x][v.y]){ d[v.x][v.y]=d[u.x][u.y]+t; if (!inq[v.x][v.y]){ inq[v.x][v.y]=1; tail=tail%M+1; h[tail]=v; } } } } } bool dfs(int x,int lim){ int i; for (i=1; i<=tot; i++) if (bo[i] && mp[x][i]<=lim){ bo[i]=0; if (!path[i] || dfs(path[i],lim)){ path[i]=x; return 1; } } return 0; } bool ok(int x){ int i,tmp=0; memset(path,0,sizeof(path)); for (i=1; i<=(cnt<<1); i++){ memset(bo,1,sizeof(bo)); if (dfs(i,x)) tmp++; } return tmp+x>=(cnt<<1); } int main(){ scanf("%d%d%d%d",&m,&n,&cnt,&pt); int i,j,x,y,t; for (i=1; i<=(cnt<<1|1); i++) scanf("%d%d",&a[i].x,&a[i].y); for (i=1; i<=pt; i++){ scanf("%d%d%d",&x,&y,&t); while (t--){ b[++tot].x=x; b[tot].y=y; } } for (i=1; i<=m; i++) for (j=1; j<=n; j++) scanf("%d",&c[i][j]); for (i=1; i<=(cnt<<1); i++){ if (i<=cnt) bfs(a[i].x,a[i].y,0); else bfs(a[i].x,a[i].y,1); for (j=1; j<=tot; j++) mp[i][j]=d[b[j].x][b[j].y]; } int l=0,r=cnt<<1,mid; while (l<r){ mid=(l+r)>>1; if (ok(mid)) r=mid; else l=mid+1; } printf("%d\n",l); return 0; }
by lych
2016.4.6
相关文章推荐
- Ultimate四则运算
- mysql case....when条件
- Chrome浏览器地址栏访问接口url,重复请求问题解决
- Chrome浏览器地址栏访问接口url,重复请求问题解决
- C# 统计字符串类型
- Web中常见概念对比——URL&URI;HTML&XML;HTTP
- cocos2d基本动作函数
- 【iOS开发】从 UIWebView 到 WKWebView--简书
- oracle case when 简单列子
- Java Dictionary 类
- 水骑士团队介绍
- SQL SERVER 2008 R2 数据库日志文件太大,如何进行清理?
- Github上传代码
- JSON教程
- Android热补丁动态修复技术(二):实战!CLASS_ISPREVERIFIED问题!
- nyoj最少步数<水一下>
- opencv轮廓检测之椭圆检测-----算法篇(7)--Hough transform检测圆
- LeetCode 260 -Single Number III ( JAVA )
- 剑指offer面试题 翻转单词顺序 VS 左旋转字符串
- 第一次使用JAVA在OJ上刷题