HD-1150-最小点覆盖

题目传送门

Sample Input
5 5 10
0 1 1
1 1 2
2 1 3
3 1 4
4 2 1
5 2 2
6 2 3
7 2 4
8 3 3
9 4 3
0

Sample Output
3

题目大意:有两台机器A和B,A机器有n种工作方式,B机器有m种工作方式。共有k个任务。每个任务恰好在一条机器上运行。 如果任务在A机器上运行,就需要转换为模式Xi,如果在B机器上运行,就需要转换为模式Yi。 每台机器上的任务可以按照任意顺序执行,但是每台机器每转换一次模式需要重启一次。 请合理为每个任务安排一台机器并合理安排顺序,使得机器重启次数尽量少。

解题思路
题目要求使机器重启的次数要尽量少,又要把所有的任务都执行完,也就可以把题目转换成最小顶点覆盖,根据二分图的性质:最小顶点覆盖=最大匹配数。emm我害怕一个任务可以由多种情况都可以到达,这个题就用网络流做了一下。感觉有点麻烦。。

可以找个数组标记一下!就是为了好玩 用一下网络流。

s向1-k个任务连一条容量为1的边 (是为了一个任务多种情况)
将第一个模式拆成两个点 i , i*,而这连一个容量为1的边 (是为了符合二分图匹配,一个点只能被用一次)
将第二个模式的每个点向t连一条容量为1的边
输入任务 模式一 模式二
任务与 i 相连容量为1 ------- i*与模式二相连容量为1
在这里插入图片描述

#include <cstdio>
#include <queue>
#include <cstring>
#define m(a,b) memset(a,b,sizeof a)
const int N=100+5;
const int M=1000+5;
const int INF=0x3f3f3f3f;
using namespace std;
typedef long long ll;
int head[3*N+M+2],d[3*N+M+2];
int tot,nx,ny,m,s,t;
struct Edge{int to,len,nex;}edge[6*M+4*N];
void add(int from,int to,int len)
{
    edge[++tot]=(Edge){to,len,head[from]};head[from]=tot;
    edge[++tot]=(Edge){from,0,head[to]};head[to]=tot;
}
queue<int>q;
bool bfs()
{
    while(!q.empty())
        q.pop();
    m(d,0);
    q.push(s);d[s]=1;
    while(!q.empty())
    {
        int x=q.front();q.pop();
        for(int i=head[x];i;i=edge[i].nex)
        {
            int y=edge[i].to,l=edge[i].len;
            if(!d[y]&&l)
            {
                q.push(y);
                d[y]=d[x]+1;
                if(y==t)
                    return 1;
            }
        }
    }
    return 0;
}
int dinic(int x,int flow)
{
    if(x==t)
        return flow;
    int res=flow,k;
    for(int i=head[x];i&&res;i=edge[i].nex)
    {
        int y=edge[i].to,l=edge[i].len;
        if(d[y]==d[x]+1&&l)
        {
            k=dinic(y,min(res,l));
            if(!k)
            {
                d[y]=0;
                continue;
            }
            edge[i].len-=k;
            edge[i^1].len+=k;
            res-=k;
        }
    }
    return flow-res;
}
int main()
{
    while(scanf("%d%d%d",&nx,&ny,&m),nx)
    {
        m(head,0);
        tot=1;
        s=0,t=m+nx+nx+ny+1;
        int id,a,b;
        for(int i=1;i<=m;i++)
            add(s,i,1);
        for(int i=m+1;i<=m+nx;i++)
            add(i,i+nx,1);
        for(int i=m+nx+nx+1;i<t;i++)
            add(i,t,1);
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&id,&a,&b);
            id++;
            add(id,m+a,1);
            add(m+nx+a,m+nx+nx+b,1);
        }
        ll maxflow=0;
        while(bfs())
            maxflow+=dinic(s,INF);
        printf("%lld\n",maxflow);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值