POJ 1087

来源:互联网 发布:lol显示网络不稳定 编辑:程序博客网 时间:2024/05/03 01:49

这是一个 网络中的最大流问题的 经典问题。

题目:

有n个插座,m个电器,k种适配器(a,b),表示插座b可以替代插座a

问最少有多少个 电器 充不到电?

这道题 可以转换为 求最多可以多少个 电器设备可插入? maxflow

那么问题的答案就是 m - maxflow


下面就是 如何求最大流 maxflow. 

增广路算法:每次用BFS找一条最短的增广路径,然后沿着这条路径修改流量值(实际修改的是残量网络的边权)。当没有增广路时,算法停止,此时的流就是最大流。

增广路 就是 一条 从源点到汇点的 一条路径。


什么是源点,什么是汇点?

在本题中,建立两个点source,sink,分别表示 源点与汇点,source点分别指向 各个 电器设备,权值为1,表示只有一个电器设备。然后将 各个电器设备 指向各自能插的 插座,权值为1,表示一个电器设备只能 插一个 插座。然后将 插座 与 可以转换的 插座相连,权值为 MAX,表示可以有无数个转换器。最后将 可以进行转换的插座 连向汇点。

问题要求的是,从源点 到 汇点 的 最大流。

#include <iostream>#include <map>#include <string>#include <queue>using namespace std;#define MAXV 500#define MAX 1<<29#define min(a,b) ((a)<(b)?(a):(b))map<string,int> rec_dev;    // 给每一个设备或者插座 一个标号,键值为0表示为新边char str[30],stmp[30];int rec_dev_sum;   //设备的编号int res[MAXV][MAXV];  // 构建的图,G=(V,E),res[i][j]表示第i点到第j点int n,m,k;int dis[MAXV];int source,sink,maxflow;  //分别表示 源点、汇点、最大流int bfs(){    int k,i;    queue<int> q;    memset(dis,-1,sizeof(dis));   //dis数组为标记数组,-1表示未访问    dis[sink] = 0;      //从汇点开始,搜索    q.push(sink);    while(!q.empty()){        k = q.front();        q.pop();        for(i=0;i<MAXV;i++){            if(dis[i]==-1&&res[i][k]){  //该点未访问过 且 第i点到第k点可达                dis[i] = dis[k] + 1;                q.push(i);            }        }        if(k == source)            return 1;    }    return 0;}int dfs(int cur,int cp){    if(cur == sink) return cp;    int temp = cp,t;    for(int i=0;i<MAXV&&temp;i++){        if(dis[i]+1 == dis[cur] && res[cur][i]){            t = dfs(i,min(res[cur][i],temp));            res[cur][i] -= t;            res[i][cur] += t;            temp -= t;        }    }    return cp-temp;}void dinic(){    maxflow = 0;   //初始化    while(bfs())    //如果存在增广路        maxflow += dfs(source,MAX);}int main(){    int i;    while(cin>>n){        memset(res,0,sizeof(res));        rec_dev.clear();        rec_dev_sum = 1;  //标号从1开始,0用来表示 源点Source        source = 0;        sink = MAXV - 1;        for(i=0;i<n;i++){            cin>>str;            rec_dev[str] = rec_dev_sum++;            res[rec_dev[str]][sink] = 1;  //插座到汇点的值为1        }        cin>>m;        for(i=0;i<m;i++){            cin>>stmp>>str;            rec_dev[stmp] = rec_dev_sum++; //给电器设备编号            if(!rec_dev[str])         //表示这是一个新的插座,加入新边                rec_dev[str] = rec_dev_sum++;            res[source][rec_dev[stmp]] = 1;   //源点到电器设备的值为1            res[rec_dev[stmp]][rec_dev[str]] = 1;  //电器设备到插座的值为1        }        cin>>k;        for(i=0;i<k;i++){            cin>>str>>stmp;            if(!rec_dev[str])   //表示这是一个新的插座,加入新边                rec_dev[str] = rec_dev_sum ++;            if(!rec_dev[stmp])                rec_dev[stmp] = rec_dev_sum ++;            res[rec_dev[str]][rec_dev[stmp]] = MAX;   //转换器 有无数个,所以 值为无穷大        }        dinic();   //求最大流算法        cout<<m-maxflow;    //电器设备总量 - 最大可以充电的设备 = 没有充电的设备    }    return 0;}


0 0
原创粉丝点击