poj 2112 最大流求二分图匹配/二分搜索

来源:互联网 发布:安阳市网络教育平台 编辑:程序博客网 时间:2024/05/17 06:46
#include<cstdio>#include<cstring>#include<string.h>#include<vector>#include<queue>#include<iostream>#include<algorithm>#define INF 0x3f3f3fusing namespace std;const int maxn=310;int c,m,k;struct edge{int to,cap,rev;};vector<edge> G[maxn];int level[maxn];int iter[maxn];int dis[maxn][maxn];void addEdge(int from,int to,int cap){    G[from].push_back((edge){to,cap,G[to].size()});    G[to].push_back((edge){from,0,G[from].size()-1});}void bfs(int s){    memset(level,-1,sizeof(level));    queue<int> que;    level[s]=0;    que.push(s);    while(!que.empty())    {        int v=que.front();        que.pop();        for(int i=0;i<G[v].size();i++){            edge &e=G[v][i];        if(e.cap>0&&level[e.to]<0)        {            level[e.to]=level[v]+1;            que.push(e.to);        }    }    }}int dfs(int v,int t,int f){    if(v==t) return f;    for(int &i=iter[v];i<G[v].size();i++)    {        edge &e =G[v][i];        if(e.cap>0&&level[v]<level[e.to])        {            int d=dfs(e.to,t,min(f,e.cap));            if(d>0)            {                e.cap-=d;                G[e.to][e.rev].cap+=d;                return d;            }        }    }    return 0;}int maxFlow(int s,int t){    int flow=0;    for(;;)    {        bfs(s);        if(level[t]<0) return flow;        memset(iter,0,sizeof(iter));        int f;        while((f=dfs(s,t,INF))>0) {flow+=f;}    }}void build(int x){        for(int i=1;i<=k;i++)            addEdge(i,k+c+1,m);        for(int j=k+1;j<=k+c;j++)            addEdge(0,j,1);             for(int j=k+1;j<=k+c;j++)               for(int i=1;i<=k;i++)                    if(dis[j][i]<=x)///建图时要弄清楚出发点和终点            {                addEdge(j,i,1);            }}int main(){    while(scanf("%d%d%d",&k,&c,&m)!=EOF)    {        //memset(iter,0,sizeof(iter));        //memset(level,0,sizeof(level));        memset(dis,0,sizeof(dis));        for(int i=1;i<=k+c;i++)            for(int j=1;j<=k+c;j++)            {scanf("%d",&dis[i][j]);            if(dis[i][j]==0)                dis[i][j]=INF;}        for(int l=1;l<=k+c;l++)            for(int i=1;i<=k+c;i++)                for(int j=1;j<=k+c;j++)                    if(dis[i][j]>dis[i][l]+dis[l][j])                 dis[i][j]=dis[i][l]+dis[l][j];        int L=0,R=100000,mid;          int tp;          while(L<R){/// 二分枚举 max_min             mid=(L+R)>>1;             for(int i=0;i<=310;i++)///一定要记得清空vector             G[i].clear();             build(mid);             tp=maxFlow(0,c+k+1);///二分图中tp(最大流)为最大匹配             //cout<<tp<<endl;             if(tp>=c) {R=mid;}             else {L=mid+1;}          }///二分建图枚举,最大流最小值。        printf("%d\n",R);    }    return 0;}

 相似的一题是UVA753(算法入门)

#include <cstdio>#include <cstring>#include <queue>using namespace std;#define INF 0x3f3f3f3f#define MAXN 250#define MAXM 40100int N,M,K,CNT,edgenum,first[MAXN],mat[MAXN],vis[MAXN],cov[MAXN];struct edge{    int u,v,next;}e[MAXM];struct  device  //电器{    char s1[30],s2[30];}d[MAXN];struct adapter //转换器{    char s1[30], s2[30];}a[MAXN];struct receptacle  //插座{    char s[30];}r[MAXN]; void add(int u , int v){    e[edgenum].u=u; e[edgenum].v=v;    e[edgenum].next=first[u];    first[u]=edgenum++;}int dfs(int j , int k)  //目标是j插座,当前是k转换器{    if(!strcmp(a[k].s2 , r[j].s))  //当前转换器能插入插座中        return 1;    vis[k]=1;  //标记k转换器被用过,在一趟dfs中一种转换器没必要被用两次    for(int i=1; i<=K; i++) if(!vis[i]) //所有没被用过的转换器        if(!strcmp(a[k].s2 , a[i].s1))                 {//另外k转换器可以插入i转换器中            if(dfs(j,i))                return 1;            vis[i]=0;        }    return 0;}int find(int i , int j)  //i电器和j插座{    memset(vis,0,sizeof(vis));    for(int k=1; k<=K; k++) //所有转换器        if(!strcmp(d[i].s2 , a[k].s1))         {//电器能插入转换器的入口            if(dfs(j,k))                return 1;            vis[k]=0;        }    return 0;}void input(){    scanf("%d",&N);    for(int i=1; i<=N; i++)        scanf("%s",r[i].s);    scanf("%d",&M);    for(int i=1; i<=M; i++)        scanf("%s%s",d[i].s1,d[i].s2);    scanf("%d",&K);    for(int i=1; i<=K; i++)        scanf("%s%s",a[i].s1,a[i].s2);     CNT=N+M+K;}void init(){    memset(first,-1,sizeof(first));    edgenum=0;    for(int i=1; i<=M; i++)  //所有电器         for(int j=1; j<=N; j++) //所有插座        {            if(!strcmp(d[i].s2 , r[j].s))  //可以直接相连            {                //printf("直接相连%d---%d\n",i,j);                add(i,j+M);  //建立有向边            }            else if(find(i,j))  //如果通过转换器能连接上            {                //printf("通过转换器连接%d---%d\n",i,j);                add(i,j+M);            }        }}void printfff(){    for(int i=0; i<edgenum; i++)        printf("%d %d %d\n",e[i].u,e[i].v,e[i].next);}int dfs_match(int u){    for(int k=first[u]; k!=-1; k=e[k].next)    {        int v=e[k].v;        if(!cov[v])        {            cov[v]=1;            if( mat[v]==-1 || dfs_match(mat[v]) )            { mat[v]=u; return 1; }        }    }    return 0;}void maxmatch(){    int max=0;    memset(mat,-1,sizeof(mat));    for(int i=1; i<=M+N; i++)  //所有的点都做一次起点    {        memset(cov,0,sizeof(cov));        max+=dfs_match(i);    }    //for(int i=1; i<=M+N; i++)        //printf("%d<--->%d\n",i,mat[i]);    //printf("max=%d\n",max);    printf("%d\n",M-max);}int main(){    int T;    scanf("%d",&T);    while(T--)    {        input();        init();       //printfff();        maxmatch();        if(T) printf("\n");    }    return 0;}

两题对比来看,都是二分图匹配问题。



原创粉丝点击