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);
}
}