P1361 小M的作物

P1361 小M的作物

二者取其一类型的网络流题

不同的集合,向对应元素连去不同(收益)容量的边

对于那些神奇的组合,我们只需要按照以下方式建立两个点

  1. \(X\)\(S\)连一条在A时的额外收益
    2.\(X\) \(X^{\star}\)(注意顺序,\(X\)是其有向边的起点,\(X^{\star}\)是其有向边的终点)向其后继节点连\(inf\)容量的边,保证不会出现在最小割中
    3.\(X^{\star}\)\(T\)连去一条在\(B\)时的的收益

然后将所有边(\(inf\)除外)的权值加起来,减去最小割就是答案

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<queue>
#include<cstring>
using std::queue;
using std::min;
const int maxn=11000;
int n,m;
struct node
{
    int p;
    long long f;
    int nxt;
};
int head[maxn<<1],tail=-1;
int cur[maxn<<1];
node line[5000000];
void add(int a,int b,long long c)
{
    line[++tail].p=b;
    line[tail].f=c;
    line[tail].nxt=head[a];
    head[a]=tail;
}
int dis[maxn<<1];
bool bfs(int s,int t)
{
    queue<int>q;
    memset(dis,0,sizeof(dis));
    dis[s]=1;
    q.push(s);
    while(!q.empty())
    {
        int pas=q.front();q.pop();
        for(int i=head[pas];i!=-1;i=line[i].nxt)
            if(!dis[line[i].p]&&line[i].f)
            {
                dis[line[i].p]=dis[pas]+1;
                q.push(line[i].p);
            }
    }
    return dis[t];
}
long long dfs(int now,int aim,long long flow)
{
    long long res=0,f;
    if(now==aim||!flow)	return flow;
    for(int &i=cur[now];i!=-1;i=line[i].nxt)
        if(dis[line[i].p]==dis[now]+1&&(f=dfs(line[i].p,aim,min(flow,line[i].f))))
        {
            res+=f;
            flow-=f;
            line[i].f-=f;
            line[i^1].f+=f;
            if(!flow) break;
        }
    return res;
}
long long dinic(int s,int t)
{
    long long res=0;
    while(bfs(s,t))
    {
        for(int i=0;i<=n+m*2+1;i++)
            cur[i]=head[i];
        res+=dfs(s,t,0x7fffffff);
    }
    return res;
}
int main()
{
	memset(head,-1,sizeof(head));
	scanf("%d",&n);
    int a,b,c,ans=0;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a);
        ans+=a;
        add(0,i,a);
        add(i,0,0);
    }
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a);
        ans+=a;
        add(i,n+1,a);
        add(n+1,i,0);
    }
    scanf("%d",&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&a,&b,&c);
        add(0,i+n+1,b);
        add(i+n+1,0,0);
        add(i+n+m+1,n+1,c);
        add(n+1,i+n+m+1,0);
        ans+=b+c;
        for(int j=1;j<=a;j++)
        {
            scanf("%d",&b);
            add(i+n+1,b,0x7fffffff);
            add(b,i+n+1,0);
            add(b,i+n+m+1,0x7fffffff);
            add(i+n+m+1,b,0);
        }
    }
    printf("%d",ans-dinic(0,n+1));
}
posted @ 2018-07-29 20:53  Lance1ot  阅读(139)  评论(0编辑  收藏  举报