网络流+拆点+源点汇点
首先题意比较难理解,大意是有p种部件和n个机器,每个机器有产量和输入输出规格
p=3的情况下,一个机器按照这种形式描述:100 0 1 2 1 1 1
意思为机器产量为100,输入电脑要求为:没有部件1,有部件2,部件3可有可无
输出部件1,2,3都有的电脑
一开始是没有任何部件的电脑,通过这些机器,要让所有部件都有的电脑产量最大
然后输出产量,机器之间的流量个数,还有流量信息(u,v,w)
把每个机器化为两个点,输入点和输出点,之间连一条边,容量就是机器产量
按照输入输出要求在机器之间加边,容量为INF
建立没有部件电脑的输出点(源点),和所有部件都有的电脑的输入点(汇点)
再和符合规格的机器加边
用网络流模板跑一遍(源点->汇点),再过一遍边得到流量信息输出
我用了ISAP模板
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
const int N=50+10;
const int M=2500+10;
const int INF=0x7f7f7f7f;
struct Edge
{
int to,nxt,cap,flow;
}edge[M];
int tot,first[N];
void addedge(int u,int v,int w,int rw=0)
{
edge[tot].to=v;edge[tot].cap=w;edge[tot].flow=0;
edge[tot].nxt=first[u];first[u]=tot++;
edge[tot].to=u;edge[tot].cap=rw;edge[tot].flow=0;
edge[tot].nxt=first[v];first[v]=tot++;
}
void init()
{
tot=0;
memset(first,-1,sizeof(first));
}
int gap[N],dep[N],pre[N],cur[N];
int sap(int s,int e,int n) //起点,终点,点个数
{
memset(gap,0,sizeof(gap));
memset(dep,0,sizeof(dep));
memcpy(cur,first,sizeof(first));
int u=s;
pre[u]=-1;
gap[0]=n;
int ans=0;
while(dep[s]<n)
{
if(u==e)
{
int Min=INF;
for(int i=pre[u];i!=-1;i=pre[edge[i^1].to])
if(Min>edge[i].cap-edge[i].flow)
Min=edge[i].cap-edge[i].flow;
for(int i=pre[u];i!=-1;i=pre[edge[i^1].to])
{
edge[i].flow+=Min;
edge[i^1].flow-=Min;
}
u=s;
ans+=Min;
continue;
}
bool flag=false;
int v;
for(int i=cur[u];i!=-1;i=edge[i].nxt)
{
v=edge[i].to;
if(edge[i].cap-edge[i].flow&&dep[v]+1==dep[u])
{
flag=true;
cur[u]=pre[v]=i;
break;
}
}
if(flag)
{
u=v;
continue;
}
int Min=n;
for(int i=first[u];i!=-1;i=edge[i].nxt)
if(edge[i].cap-edge[i].flow&&dep[edge[i].to]<Min)
{
Min=dep[edge[i].to];
cur[u]=i;
}
gap[dep[u]]--;
if(!gap[dep[u]]) return ans;
dep[u]=Min+1;
gap[dep[u]]++;
if(u!=s) u=edge[pre[u]^1].to;
}
return ans;
}
int q[N];
int g[N][N];
int main()
{
int p,n;
while(~scanf("%d%d",&p,&n))
{
init();
for(int i=0;i<2*p;i++)
g[0][i]=0;
for(int i=0;i<2*p;i++)
g[2*n+1][i]=1;
for(int i=1;i<=2*n;i+=2)
{
scanf("%d",&q[i]);
addedge(i,i+1,q[i],0);
for(int j=0;j<p;j++)
scanf("%d",&g[i][j]);
for(int j=0;j<p;j++)
scanf("%d",&g[i+1][j]);
}
for(int i=1;i<=2*n+1;i+=2)
{
for(int j=0;j<=2*n;j+=2)
{
bool flag=true;
for(int k=0;k<p;k++)
if(g[i][k]!=g[j][k]&&g[i][k]!=2&&g[j][k]!=2)
{
flag=false;
continue;
}
if(flag)
addedge(j,i,INF,0);
}
}
int ans=sap(0,2*n+1,2*n+2);
int cnt=0;
for(int i=2;i<=2*n;i+=2)
{
for(int j=first[i];j!=-1;j=edge[j].nxt)
if(edge[j].flow>0&&edge[j].to!=2*n+1) cnt++;
}
printf("%d %d\n",ans,cnt);
for(int i=2;i<=2*n;i+=2)
{
for(int j=first[i];j!=-1;j=edge[j].nxt)
if(edge[j].flow>0&&edge[j].to!=2*n+1)
printf("%d %d %d\n",i/2,edge[j].to/2+1,edge[j].flow);
}
}
return 0;
}