UVA 11419 SAM I AM 网络流
2017-08-15 14:59
211 查看
今天是在家待的最后一天了……在家的15天一直没有写过博客,今天还是写一篇吧。
用网络流做二分图的基本定理:
最大点权独立=总点权-最小点权覆盖
最大点权独立集:点和点之间没有边相连接
最小点权覆盖集:每一条边都有一个点被点亮,所有点的点权之和最小
这道题可转换为求最小点权覆盖集,也就是求最小割
怎么建图是我看了别人的,二分图的X集对应行号,Y集对应列号,把每个敌人的行号和列号相连。
之后求答案的方式很简单,跑个最小割即可。但我又不知道怎么输出割的是哪几条边,所以再次看了别人的。
做法详见代码。
以下是关于此做法(get_ans)的感性认知:
如果是这样
——1—
S—-2—(123汇集于5)5—-T
——3—
(假设S—1边满流)
很明显我们要割5—T这条边。在get_ans时我们可以通过一条未满流的边到达5,因此2和3都会被访问。
那么1如何被访问呢?
当访问到5时 1->5的反向边cap=0 flow>0 满足条件,返回访问1。
如果是这样
—–2—-
S—1 —–3—-(2 3 4汇集与T)
—–4—-
那么1肯定满流 访问不了,因此2 3 4也访问不了 。
注意flow[i]和w[i]的加减变化刚好相反,这点也比较容易理解
flow流量 既然流过了 自然要加 反向边当然要减
而w可理解为还有多少流量可以走 流过自然要减
思路:
这道题我用的是网络流。(好吧其实是因为不会KM算法)用网络流做二分图的基本定理:
最大点权独立=总点权-最小点权覆盖
最大点权独立集:点和点之间没有边相连接
最小点权覆盖集:每一条边都有一个点被点亮,所有点的点权之和最小
这道题可转换为求最小点权覆盖集,也就是求最小割
怎么建图是我看了别人的,二分图的X集对应行号,Y集对应列号,把每个敌人的行号和列号相连。
之后求答案的方式很简单,跑个最小割即可。但我又不知道怎么输出割的是哪几条边,所以再次看了别人的。
做法详见代码。
以下是关于此做法(get_ans)的感性认知:
如果是这样
——1—
S—-2—(123汇集于5)5—-T
——3—
(假设S—1边满流)
很明显我们要割5—T这条边。在get_ans时我们可以通过一条未满流的边到达5,因此2和3都会被访问。
那么1如何被访问呢?
当访问到5时 1->5的反向边cap=0 flow>0 满足条件,返回访问1。
如果是这样
—–2—-
S—1 —–3—-(2 3 4汇集与T)
—–4—-
那么1肯定满流 访问不了,因此2 3 4也访问不了 。
注意:
不能再用w[i]的写法了,应用cap[i]和flow[i]注意flow[i]和w[i]的加减变化刚好相反,这点也比较容易理解
flow流量 既然流过了 自然要加 反向边当然要减
而w可理解为还有多少流量可以走 流过自然要减
#include<cstdio> #include<cstring> #include<queue> #define INF 10000000 using namespace std; const int P=2500,E=2008106; int r,c,n; int T,S; int to[E],nxt[E],cap[E],flow[E],head[P],etot; int dis[P]; bool vis[P],foot[P]; void adde(int u,int v,int c) { to[++etot]=v; nxt[etot]=head[u]; cap[etot]=c; head[u]=etot; } void ins(int u,int v,int c) { adde(u,v,c); adde(v,u,0); } bool bfs() { memset(dis,-1,sizeof(dis)); queue<int> q; q.push(S); dis[0]=0; while(!q.empty()){ int u=q.front();q.pop(); for(int i=head[u];i;i=nxt[i]){ int v=to[i]; if(cap[i]-flow[i]>0&&dis[v]==-1){ dis[v]=dis[u]+1; q.push(v); } } } return dis[T]==-1?0:1; } int dfs(int u,int a) { if(u==T||a==0) return a; int used=0,f; for(int i=head[u];i;i=nxt[i]){ int v=to[i]; if(dis[v]==dis[u]+1&&cap[i]-flow[i]>0){ f=dfs(v,min(a-used,cap[i]-flow[i])); used+=f; flow[i]+=f;flow[i^1]-=f;//!! if(used==a) return used; } } if(!used) dis[u]=-1; return used; } void dinic() { int ans=0; while(bfs()){ ans+=dfs(S,INF); } printf("%d ",ans); } void get_ans(int u) { foot[u]=1; for(int i=head[u];i;i=nxt[i]) if(cap[i]-flow[i]>0&&!foot[to[i]]) get_ans(to[i]); } void init() { etot=1; memset(vis,0,sizeof(vis)); memset(head,0,sizeof(head)); memset(foot,0,sizeof(foot)); memset(cap,0,sizeof(cap)); memset(flow,0,sizeof(flow)); } int main() { while(scanf("%d%d%d",&r,&c,&n)&&(n||c||r)){ init(); T=r+c+1,S=0; for(int i=1;i<=n;i++){ int x,y; scanf("%d%d",&x,&y); ins(x,r+y,INF); if(!vis[x]){ ins(S,x,1); vis[x]=1; } if(!vis[r+y]){ ins(r+y,T,1); vis[r+y]=1; } } dinic(); get_ans(S); for(int i=1;i<=r;i++) if(vis[i]&&!foot[i]) printf("r%d ",i); for(int i=r+1;i<=r+c;i++) if(vis[i]&&foot[i]) printf("c%d ",i-r); printf("\n"); } return 0; }
相关文章推荐
- uva11419——SAM I AM——————【最小覆盖数、打印最小覆盖】
- UVA 11419 SAM I AM (二分图,最小割)
- UVA - 11419 SAM I AM
- SAM I AM UVA - 11419 最小点集覆盖 要输出具体覆盖的行和列。
- UVALive 11419 SAM I AM (最小点覆盖输出)
- UVA 11419 SAM I AM
- UVA -11419 SAM I AM 最小边覆盖输出路径
- UVA 11419 SAM I AM
- UVA - 11419 SAM I AM
- uva11419 SAM I AM(最小顶点覆盖+输出顶点)
- UVA 11419 SAM I AM(二分图最小点覆盖)
- UVa 11419 SAM I AM
- UVA 11419 - SAM I AM(二分图匹配+最小点覆盖)
- UVA-11419 SAM I AM (最小点覆盖)
- UVA 11419 SAM I AM 二分图+最小覆盖点
- Uva-11419-SAM I AM
- UVA11419[SAM I AM] 二分图最小覆盖模型
- UVa 11419 SAM I AM (最小点覆盖,匈牙利算法)
- uva 11419 SAM I AM (最小覆盖 König定理)
- UVA 11419 SAM I AM 二分匹配最小覆盖点