UVA 11419 SAM I AM 网络流

来源:互联网 发布:易经软件 知乎 编辑:程序博客网 时间:2024/06/11 17:11

今天是在家待的最后一天了……在家的15天一直没有写过博客,今天还是写一篇吧。

思路:

这道题我用的是网络流。(好吧其实是因为不会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 10000000using 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;} 
原创粉丝点击