题目链接
题目大意:要求经过每个点的流量不超过该点承载的流量上限,求最大流
思路:将a拆成a1和a2,a1作为输入端,a2作为输出端,a1->a2的边权为流量上限
#include <bits/stdc++.h>
using namespace std;
const int N = 2*100;
const int M = N*N;
int n,m,s,t,tot;
int head[N];
struct node{
int u,nxt,cap,to,old;
}edge[M<<1];
int cur[N],deep[N],p[N],in[N][20],out[N][20];
bool check(int a,int b){ //检查是否可以a->b
int i;
for(i = 1;i <= m;i ++){
if(in[b][i]==1&&out[a][i]==0) return 0;
if(in[b][i]==0&&out[a][i]==1) return 0;
}
return 1; //当时没写return 1本地居然过了,提交wa
}
void ae(int u,int v,int w){
tot++;
edge[tot].nxt = head[u];
edge[tot].to = v;
edge[tot].u = u;
edge[tot].old = w; //备份流量
edge[tot].cap = w;
head[u] = tot;
}
bool bfs(){
memset(deep,-1,sizeof(deep));
queue<int>q;
q.push(s);
deep[s] = 0;
while(!q.empty()){
int u = q.front();
for(int i = head[u]; ~i;i = edge[i].nxt){
int v = edge[i].to;
if(deep[v]==-1&&edge[i].cap>0){
q.push(v);
deep[v] = deep[u]+1;
if(v==t) return 1;
}
}
q.pop();
}
return 0;
}
int dfs(int u,int f){
int flow = 0,d;
if(u==t||f==0) return f;
for(int &i = cur[u]; ~i;i = edge[i].nxt){
int v = edge[i].to;
if(deep[v]>deep[u]&&edge[i].cap>0&&(d=dfs(v,min(f,edge[i].cap)))){
edge[i].cap -= d;
edge[i^1].cap += d;
f -= d;
flow += d;
if(!f) break;
}
}
if(flow==0) deep[u] = -1;
return flow;
}
int dinic(){
int ans = 0;
while(bfs()){
memcpy(cur, head, sizeof(head));
ans += dfs(s,1e9);
}
return ans;
}
int hs(int x){
if(x%2==1) return x/2+1;
else return x/2;
}
int main()
{
freopen("a.txt","r",stdin);
ios::sync_with_stdio(0);
cin>>m>>n;
s = 0;
t = 2*n+1;
memset(head,-1,sizeof(head));
tot = -1;
int i,j;
for(i = 1;i <= n;i ++){
cin>>p[2*i];
ae(2*i-1,2*i,p[2*i]); //拆点连边
ae(2*i,2*i-1,0);
for(j = 1;j <= m;j ++) cin>>in[2*i-1][j];
for(j = 1;j <= m;j ++) cin>>out[2*i][j];
}
p[0] = 1e9;
for(i = 1;i <= m;i ++) in[2*n+1][i] = 1;
for(i = 0;i <= 2*n;i += 2)
for(j = 1;j <= 2*n+1;j += 2){
if(check(i,j)){
if(i-1==j)continue; //防止重复建边
ae(i,j,p[i]); //建图,其实可以把p[i]改成1e9.....
ae(j,i,0);
}
}
cout<<dinic()<<' ';
int use = 0,k;
for(i = 2*n;i <= tot;i += 2){
if(k = edge[i].old-edge[i].cap){
int u = edge[i].u;
int v = edge[i].to;
if(u==0||v==2*n+1)continue;
use ++;
}
}
cout<<use<<endl;
for(i = 2*n;i <= tot;i += 2){ //跳过拆点产生的路径
if(k = edge[i].old-edge[i].cap){
int u = edge[i].u;
int v = edge[i].to;
if(u==0||v==2*n+1)continue; //跳过s和t
cout<<hs(u)<<' '<<hs(v)<<' '<<k<<endl;
}
}
return 0;
}