POJ1087DFS+匈牙利或者DINIC

题意:
     有n个插孔,m个电器,q种转换器(转换器可以无限用),然后问你最多有多少个电器能充电。


思路:
      比较简单,就是在建图的时候要考虑下,我用了两种方法做的,一个是最大流,这个方法我的建图是这样,先给每个用电器虚拟出来一个点n,每个插座虚拟出来两个点(限流)m,然后给每个插座或者是插头的类型虚拟出来一个点,这样就ok了,建图是这样
s         -> 所有用电器       1
所有用电器->他所连接的种类    1
种类      ->种类             INF   这个是转换器
种类      ->插座              1
插座到    ->插座              1    限流
插座      -> t                1
然后一遍s到t的最大流


另一种方法是用二分匹配,这个方法我们可以这样想,建立二分图,左边是用电器,右边是插座,然后用电器和插座能连的条件是可以直接或者间接连接上,这个地方可以用搜索搞定,这样在处理所有连接关系的时候的时间复杂度一共是n^2的,一开始想用Floyd了,考虑到那样的话最坏的情况会达到500*500*500就没用,通过搜索建立间接之后就可以直接匈牙利匹配了,下面是两种方法的代码。




DINIC
#include<map>
#include<queue>
#include<stdio.h>
#include<string>
#include<string.h>


#define N_node 700 + 10
#define N_edge 700 * 700 + 50
#define INF 1000000000


using namespace std;


typedef struct
{
    int to ,cost ,next;
}STAR;


typedef struct
{
    int x ,t;
}DEP;


STAR E[N_edge];
DEP xin ,tou;
map<string ,int>mark;
int deep[N_node];
int list[N_node] ,listt[N_node] ,tot;


void add(int a ,int b ,int c)
{
    E[++tot].to = b;
    E[tot].cost = c;
    E[tot].next = list[a];
    list[a] = tot;


    E[++tot].to = a;
    E[tot].cost = 0;
    E[tot].next = list[b];
    list[b] = tot;
}


int minn(int x ,int y)
{
    return x < y ? x : y;
}


bool BFS_DEEP(int s ,int t ,int n)
{
    memset(deep ,255 ,sizeof(deep));
    xin.x = s ,xin.t = 0;
    queue<DEP>q;
    q.push(xin);
    deep[s] = 0;
    while(!q.empty())
    {
        tou = q.front();
        q.pop();
        for(int k = list[tou.x] ;k ;k = E[k].next)
        {
            xin.x = E[k].to;
            xin.t = tou.t + 1;
            if(deep[xin.x] != -1 || !E[k].cost)
            continue;
            deep[xin.x] = xin.t;
            q.push(xin);
        }
    }
    for(int i = 0 ;i <= n ;i ++)
    listt[i] = list[i];
    return deep[t] != -1;
}




int DFS_Flow(int s ,int t ,int flow)
{
    if(s == t) return flow;
    int nowflow = 0;
    for(int k = listt[s] ;k ;k = E[k].next)
    {
        listt[s] = k;
        int to = E[k].to ,c = E[k].cost;
        if(!c || deep[to] != deep[s] + 1)
        continue;
        int tmp = DFS_Flow(to ,t ,minn(c ,flow - nowflow));
        nowflow += tmp;
        E[k].cost -= tmp;
        E[k^1].cost += tmp;
        if(flow == nowflow)
        break;
    }
    if(!nowflow) deep[s] = 0;
    return nowflow;
}


int DINIC(int s ,int t ,int n)
{
    int ans = 0;
    while(BFS_DEEP(s ,t ,n))
    {
        ans += DFS_Flow(s ,t ,INF);
    }
    return ans;
}


int main ()
{
    int n ,m ,q ,i;
    char str1[25+5] ,str2[25+5];
    while(~scanf("%d" ,&n))
    {
        memset(list ,0 ,sizeof(list));
        tot = 1;
        mark.clear();
        int nowid = 0;
        int s = 0 ,t = 705;
        for(i = 1 ;i <= n ;i ++)
        {
            scanf("%s" ,str1);
            if(!mark[str1]) mark[str1] = ++nowid;
            add(mark[str1] + 200 ,mark[str1] + 600 ,1);
            add(mark[str1] + 600 ,i + 100 ,1);
            add(i + 100 ,t ,1);
        }
        scanf("%d" ,&m);
        for(i = 1 ;i <= m ;i ++)
        {
            scanf("%s %s" ,str1 ,str2);
            if(!mark[str2]) mark[str2] = ++nowid;
            add(s ,i ,1);
            add(i ,mark[str2] + 200 ,1);
        }
        scanf("%d" ,&q);
        for(i = 1 ;i <= q ;i ++)
        {
            scanf("%s %s" ,str1 ,str2);
            if(!mark[str1]) mark[str1] = ++nowid;
            if(!mark[str2]) mark[str2] = ++nowid;
            add(mark[str1] + 200 ,mark[str2] + 200 ,INF);
        }
        printf("%d\n" ,m - DINIC(s ,t ,705));
    }
    return 0;
}


匈牙利+DFS
#include<map>
#include<stdio.h>
#include<string>
#include<string.h>


#define N_node 500
#define N_edge 500 * 500 + 10
#define INF 100000000


using namespace std;


typedef struct
{
    int to ,next;
}STAR;


STAR E[N_edge];
int mkdfs[N_node] ,mkgx[N_node];
int list[N_node] ,tot;
int _map[N_node][N_node];
int cz[N_node] ,dq[N_node];
map<string ,int>mark;


void add(int a ,int b)
{
    E[++tot].to = b;
    E[tot].next = list[a];
    list[a] = tot;
}


void DFS(int s ,int now)
{
    for(int k = list[now] ;k ;k = E[k].next)
    {
        int to = E[k].to;
        if(mkdfs[to]) continue;
        mkdfs[to] = _map[s][to] = 1;
        DFS(s ,to);
    }
    return ;
}


int DFS_XYL(int x)
{
    for(int k = list[x] ;k ;k = E[k].next)
    {
        int to = E[k].to;
        if(mkdfs[to]) continue;
        mkdfs[to] = 1;
        if(mkgx[to] == -1 || DFS_XYL(mkgx[to]))
        {
            mkgx[to] = x;
            return 1;
        }
    }
    return 0;
}


int main ()
{
    int n ,m ,q ,i ,j ,a ,b;
    char str1[30] ,str2[30];
    while(~scanf("%d" ,&n))
    {
        mark.clear();
        int nowid = 0;
        for(i = 1 ;i <= n ;i ++)
        {
            scanf("%s" ,str1);
            if(!mark[str1]) mark[str1] = ++nowid;
            cz[i] = mark[str1];
        }
        scanf("%d" ,&m);
        for(i = 1 ;i <= m ;i ++)
        {
            scanf("%s %s" ,str1 ,str2);
            if(!mark[str2]) mark[str2] = ++nowid;
            dq[i] = mark[str2];
        }
        memset(list ,0 ,sizeof(list));
        tot = 1;
        scanf("%d" ,&q);
        for(i = 1 ;i <= q ;i ++)
        {
            scanf("%s %s" ,str1 ,str2);
            if(!mark[str1]) mark[str1] = ++nowid;
            if(!mark[str2]) mark[str2] = ++nowid;
            add(mark[str1] ,mark[str2]);
        }
        memset(_map ,0 ,sizeof(_map));
        for(i = 1 ;i <= nowid ;i ++)
        {
            memset(mkdfs ,0 ,sizeof(mkdfs));
            _map[i][i] = 1;
            DFS(i ,i);
        }
        memset(list ,0 ,sizeof(list));
        tot = 1;
        for(i = 1 ;i <= m ;i ++)
        for(j = 1 ;j <= n ;j ++)
        if(_map[dq[i]][cz[j]]) add(i ,j);
        int ans = 0;
        memset(mkgx ,255 ,sizeof(mkgx));
        for(i = 1 ;i <= nowid ;i ++)
        {
            memset(mkdfs ,0 ,sizeof(mkdfs));
            ans += DFS_XYL(i);
        }
        printf("%d\n" ,m - ans);
    }
    return 0;
}















  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值