这题建图是个难点,不过可以浪费点空间建图,那就是输入的起点为i,终点为i+n,那么每个输入的点都不会有冲突,只是对空间有一点浪费,不过本题数据量不大,所以没关系。另一个难点就是寻找路径,参考了别人的代码之后,发现路径其实就是反向构建残余网络时建立的,以前内部建图是从i+n到j,那么map[i+n][j]是有数值的,而map[j][i+n]是没有的,现在Dinic算法过后,map[j][i+n]有数值了,因为这就是反向路径,也就是之前走过的路径,所以只要找出这些路径即可,这应该作为一个结论记住,反向有值的路就是走过的路。
//
// main.cpp
// Richard
//
// Created by 邵金杰 on 16/8/11.
// Copyright © 2016年 邵金杰. All rights reserved.
//
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<vector>
#include<cmath>
#include<cstring>
#include<queue>
using namespace std;
#define INF 100000000
const int maxn=100+10;
int map[maxn][maxn],Layer[maxn],vis[maxn];
int in[maxn][maxn],out[maxn][maxn];
int p,n;
int s[maxn],e[maxn],w[maxn];
int cnt=0;
bool is_in(int in[maxn][maxn],int i)
{
for(int j=1;j<=p;j++)
if(in[i][j]==1) return false;
return true;
}
bool is_out(int out[maxn][maxn],int i)
{
for(int j=1;j<=p;j++)
if(out[i][j]!=1) return false;
return true;
}
bool connect(int in[][maxn],int out[][maxn],int i,int j)
{
for(int k=1;k<=p;k++)
if(in[i][k]+out[j][k]==1) return false;
return true;
}
bool CountLayer(int start,int end)
{
memset(Layer,-1,sizeof(Layer));
queue<int> q;
q.push(start);
Layer[start]=0;
while(!q.empty())
{
int v=q.front();
q.pop();
for(int i=1;i<=end;i++)
{
if(map[v][i]&&Layer[i]==-1)
{
Layer[i]=Layer[v]+1;
if(i==end) return true;
else q.push(i);
}
}
}
return false;
}
int dfs(int start,int end)
{
memset(vis,0,sizeof(vis));
vector<int> v;
v.push_back(start);
vis[start]=1;
int maxflow=0;
while(v.size())
{
int nd=v[v.size()-1];
if(nd==end)
{
int minflow=INF;
int minposition=0;
for(int i=1;i<v.size();i++)
{
int p1=v[i-1];
int p2=v[i];
if(map[p1][p2]<minflow)
{
minflow=map[p1][p2];
minposition=p1;
}
}
maxflow+=minflow;
for(int i=1;i<v.size();i++)
{
int p1=v[i-1];
int p2=v[i];
map[p1][p2]-=minflow;
map[p2][p1]+=minflow;
}
int flag=0;
for(int i=0;i<v.size();i++)
if(minposition==v[i]) {flag=i;break;}
while(v.size()&&v[v.size()-1]!=minposition)
{
vis[v[v.size()-1]]=0;
v.pop_back();
}
}
else
{
int i;
for(i=1;i<=end;i++)
{
if(map[nd][i]&&!vis[i]&&Layer[i]==Layer[nd]+1)
{
vis[i]=1;
v.push_back(i);
break;
}
}
if(i>end) v.pop_back();
}
}
return maxflow;
}
int Dinic(int start,int end)
{
int ans=0;
while(CountLayer(start,end))
{
ans+=dfs(start,end);
}
return ans;
}
void FindPath()
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(i!=j&&map[j][i+n]>0)
{
s[cnt]=i;
e[cnt]=j;
w[cnt]=map[j][i+n];
cnt++;
}
}
}
}
int main()
{
while(scanf("%d%d",&p,&n)!=EOF)
{
cnt=0;
memset(s,0,sizeof(s));
memset(e,0,sizeof(e));
memset(w,0,sizeof(w));
memset(map,0,sizeof(map));
int start=0,end=2*n+1;
int c;
for(int i=1;i<=n;i++)
{
scanf("%d",&c);
map[i][i+n]=+c;
for(int j=1;j<=p;j++)
scanf("%d",&in[i][j]);
for(int j=1;j<=p;j++)
scanf("%d",&out[i][j]);
if(is_in(in,i)) {map[start][i]=INF;}
if(is_out(out,i)) {map[i+n][end]=INF;}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(connect(in,out,i,j)) {map[j+n][i]=INF;}
}
}
// for(int i=0;i<=end;i++)
// {
// for(int j=0;j<=end;j++)
// {
// cout<<map[i][j]<<" ";
// }
// cout<<endl;
// }
int ans=Dinic(start,end);
FindPath();
printf("%d %d\n",ans,cnt);
for(int i=0;i<cnt;i++)
{
printf("%d %d %d\n",s[i],e[i],w[i]);
}
}
return 0;
}