Direction Setting(2021 SCCPC F)

Gym - 103117F

题目大意

T组询问,每组询问给你n个点和m条边,每个点有一个边权ai,现在让你确定每条边的方向,定义di为第i个点的入度,使得D=i=1nmax(0,diai)最小。问D的最小值与每条边的方向,输出任一方案即可。(2n300,1m300,0ai104,n3×103,m3×103)

思路

我们考虑网络流,我们对起点和每条边都连一条流量为1的边,对每条边和它的端点连一条流量为1的边,再对每个点和汇点连一条流量为ai的边,然后我们跑一遍Dinic,最后的mdinic就是最小的D,然后对于每条边,它流向的某个端点的边中流量如果还是1,那么说明这条边是往还有一个方向流的,反之亦然,于是我们就完成构造了。

代码

#include<bits/stdc++.h>
using namespace std;
const int MAXN=1000005;
const int inf=1000000000;
int S,T;
struct EDGE
{
    int v,flow,nxt;
}edge[MAXN<<2];
int head[MAXN],cur[MAXN],num=0;
int dep[MAXN],q[MAXN];
void add_edge(int u,int v,int w)
{
    edge[num].v=v;
    edge[num].flow=w;
    edge[num].nxt=head[u];
    head[u]=num++;
}
void Add_edge(int u,int v,int w)
{
    add_edge(u,v,w);
    add_edge(v,u,0);
}
bool bfs()
{
    memset(dep,0,sizeof(dep));
    dep[S]=1;
    int l=0,r=1;
    q[++l]=S;
    while(l<=r)
    {
        int p=q[l++];
        for(int i=head[p];~i;i=edge[i].nxt)
        {
            if(!dep[edge[i].v]&&edge[i].flow)
            {
                dep[edge[i].v]=dep[p]+1;
                q[++r]=edge[i].v;
                if(edge[i].v==T)return 1;
            }
        }
    }
    return dep[T];
}
int dfs(int now,int nowflow)
{
    if(now==T)return nowflow;
    int totflow=0;
    for(int i=head[now];~i;i=edge[i].nxt)
    {
        if(dep[edge[i].v]==dep[now]+1&&edge[i].flow)
        {
            int canflow=dfs(edge[i].v,min(nowflow,edge[i].flow));
            edge[i].flow-=canflow;
            edge[i^1].flow+=canflow;
            totflow+=canflow;
            nowflow-=canflow;
            if(nowflow<=0)break;
        }
    }
    return totflow;
}
int dinic()
{
    int ans=0;
    while(bfs())
    {
        memcpy(cur,head,sizeof(head));
        ans+=dfs(S,inf);
    }
    return ans;
}
void init()
{
    memset(q,0,sizeof(q));
    memset(cur,0,sizeof(cur));
    memset(dep,0,sizeof(dep));
    memset(head,-1,sizeof(head));
    for(int i=0;i<=num;i++)edge[i].v=edge[i].flow=edge[i].nxt=0;
    num=0;
}
int main()
{
    int _;
    scanf("%d",&_);
    while(_--)
    {
        init();
        int n,m;
        scanf("%d%d",&n,&m);
        S=601,T=602;
        for(int i=301;i<=m+300;i++)Add_edge(S,i,1);
        for(int i=1;i<=n;i++)
        {
            int a;
            scanf("%d",&a);
            Add_edge(i,T,a);
        }
        for(int i=301;i<=m+300;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            Add_edge(i,u,1);
            Add_edge(i,v,1);
        }
        printf("%d\n",m-dinic());
        for(int i=2*m+2*n+1;i<=2*m+2*n+4*m;i+=4)
        {
            if(edge[i].flow==1)printf("1");
            else printf("0");
        }
        printf("\n");
    }
    return 0;
}
/*
2
4 5
0 1 1 5
1 2
1 3
2 3
3 2
4 4
3 2
0 0 2
1 3
3 2
*/

__EOF__

本文作者Jerry-Black
本文链接https://www.cnblogs.com/Jerry-Black/p/16064369.html
关于博主:小蒟蒻一只( ̄^ ̄)ゞ
版权声明:转载请注明来源哟~ QAQ
声援博主:UP UP UP !!!
posted @   Jerry_Black  阅读(55)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示