首页 > 其他分享 >P9705 「TFOI R1」Unknown Graph题解

P9705 「TFOI R1」Unknown Graph题解

时间:2024-09-20 09:14:53浏览次数:9  
标签:cnt R1 val int 题解 出度 建模 Unknown include

思路

题目给出了每个点的初度和入度,由于图是无重边无自环的有向图

要求满足限制的图有多少条边与建图方案。

我们可以考虑使用网络流中的最大流

我们知道这是一道网络流后,题目的难点就转移到网络流的建模以及输出方案的办法。

网络流的建模:

题目所给的条件没有源点汇点并指出图可以不连通,所以考虑设立一个超级源点 \(S\) 以及汇点 \(T\)。

由于有入度和初度的要求,图是有向图

考虑拆点

将每一个点拆成两个点,一个代表由其他点连向自己,即入度。

反之同理,另一个点代表自己连向其他点,即出度。

针对由有些边不能连,由于本题数据较小,我们可以使用一个邻接矩阵来存该边可不可以连。

注意:没有自环,所以自己不能连自己。

所以综上所述,本题的建模规则:

1:每个点的入度连向汇点流量为入度 \(a _ {i}\)

2:源点连向每个点的出度流量为出度 \(b _ {i}\)

3:可以连的边,起点的出度点连向终点的入读点流量为 1没有重边)。

保证有解,所以建模规则 1 和 2 中的连的边满流。

然后就可以跑一遍最大流 Dinic 板子。

输出方案:

连的边必然是建模规则 3 中连的边,当该边被选中时必然满流(因为流量只有 1)。

但这种边一定是由出度点连向入读点。

下面给出代码:

代码

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define inf 1e9
using namespace std;
int n,m,s,t;
int mapp[1005][1005]; 

int cnt=-1;
struct N{
    int from,to,next,val;
};N p[10000005];
int head[8005],cur[8005],d[8005];

inline void add(int a,int b,int c)
{
    ++cnt;
    p[cnt].from=a;
    p[cnt].next=head[a];
    head[a]=cnt;
    p[cnt].to=b;
    p[cnt].val=c;
    return ;
}

inline int bfs()
{
    queue<int> q;
    q.push(s);
    memset(d,-1,sizeof(d));
    d[s]=0;
    while(q.size()>0)
    {
        int u=q.front();
        q.pop();
        for(int i=head[u];i!=-1;i=p[i].next)
        {
            int v=p[i].to;
            if(d[v]==-1&&p[i].val>0)
            {
                d[v]=d[u]+1;
                q.push(v);
            }
        }
    }
    if(d[t]==-1) return 0;
    else return 1;
}

inline int dfs(int u,int limit)
{
    if(u==t||!limit) return limit;
    int sum=0,flow=0;
    for(int i=cur[u];i!=-1;i=p[i].next)
    {
        int v=p[i].to;
        cur[u]=i;
        if(d[v]==d[u]+1&&p[i].val>0)
        {
            sum=dfs(v,min(p[i].val,limit));
            p[i].val-=sum;
            p[i^1].val+=sum;
            flow+=sum;
            limit-=sum;
            if(!limit) break;
        }
    }
    if(!flow) d[u]=-1;
    return flow;
}

inline void dinic()
{
    int ans=0;
    while(bfs())
    {
        for(int i=0;i<=t;i++) cur[i]=head[i];
        ans+=dfs(s,inf);
    }
    cout<<ans<<endl;
    return ;
}//板子 

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    memset(head,-1,sizeof(head));//s=0,memset head数组为-1 
    cin>>n;
    s=0,t=2*n+1;
    int a,b;
    for(int i=1;i<=n;i++)
    {
        cin>>a;
        add(i+n,t,a),add(t,i+n,0);//建模规则1 
    }
    for(int i=1;i<=n;i++)
    {
        cin>>a;
        add(s,i,a),add(i,s,0);//建模规则2
    }
    //拆点:这里我们将出度点的编号设为1-n,入度点就是n+1-2*n,所以汇点t可设为2*n+1 
    cin>>m;
    for(int i=1;i<=m;i++)
    {
        cin>>a>>b;
        mapp[a][b]=1;//邻接矩阵
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(mapp[i][j]==0&&i!=j)//当此边没有被限制且不是自己连向自己时 
            {
                add(i,n+j,1),add(n+j,i,0);//连边 
            }
        }
    }
    dinic();
    for(int i=4*n-1;i<=cnt;i++)//建图规则3中连的边cnt值从4*n-1到cnt 
    {
        if(i%2==0&&p[i].val==0)//是从出度连向入度的边且满流了(val值为0) 
        {
            cout<<p[i].from<<" "<<p[i].to-n<<endl;//输出时入度点要记得减去n 
        }
    }
    return 0;
} 

标签:cnt,R1,val,int,题解,出度,建模,Unknown,include
From: https://www.cnblogs.com/call-of-silence/p/18421806

相关文章

  • P5979 [PA2014] Druzyny 题解
    对于一个固定的右端点\(r\),左端点\(l\)合法当且仅当\(\max(d_l,d_{l+1},\dotsd_r)\ler-l+1\le\min(c_l,c_{l+1},\dots,c_r)\)。容易得到一个很朴素的dp:记\(f_i\)表示前\(i\)个位置可以分成的组的数目的最大值,\(g_i\)表示有多少种分组方案能达到最大值,直接枚举左端点......
  • CF2004G 题解
    题意定义关于数字串\(s\)的函数\(f(s)\)表示将\(t\)切分为\(m\)段,要求\(m\)是偶数,假设这些字符串分别为\(t_1,t_2,\ldots,t_m\),有\(s=t_1+t_2+\ldots+t_m\)。定义\(A^x\)表示\(\underbrace{AA\ldotsAA}_{x~\text{times}}\),求一种划分方式,使得\(t_2^......
  • P1108 低价购买 题解
    这题在求最长下降子序列的基础上加了一个求方案数的要求,这就让这道题目变难了很多。我们考虑我们在求最长下降子序列的时候,总是从这一位,要么重新开始计数,要么只和前面的有关,所以前面的信息完全丢失了,无法判断有多少方案,所以我们就要针对前面的方案数设计一个dp来统计。可以称之......
  • 题解:CF1906F Maximize The Value
    可以在cnblog中阅读。见这种题比较少,写篇题解加深印象。如果直接上数据结构维护数组,似乎没有好的办法处理操作序列的一个子段。那不妨转变思路,对操作序列上数据结构维护。假设顺序进行每个修改操作,我们用时间表示修改操作的编号,位置表示数组的下标,则常见的维护序列的数据结构......
  • 蓝桥杯十五届软件赛C++B组题解
    最近蓝桥杯官网已经把十五届题目上架了,我会尽快的将题解发出来,没有发的过段时间再补。​​​​​​​数字接龙一个很鹅心的搜索题,一不注意就会写错,比赛的时候写不来,题目上架后也WA了两个样例才过。题目大意:也就是说从(1,1)开始 ,下一步路的数据总是要比当前数据大1,超过k就......
  • P2051 [AHOI2009] 中国象棋 题解
    DP好题?首先确定,每一行/列只能放至多两个棋子,这么少,所以我们的状态肯定和棋子数有关。由于我们不关注具体的方案数,所以我们不妨只关心对应棋子数量的行/列的数量。同时,由于考虑行和列都是一样的,所以我们不妨用行递推。所以我们设$\dp_{i,j,k}\$表示当前放到第\(i\)行,有\(......
  • Capital许可使用常见问题解答
    在使用Capital软件的过程中,许多用户可能会遇到关于许可使用的各种问题。为了帮助大家更好地理解和合规使用Capital软件,我们整理了一份常见问题解答,希望能为您提供有价值的参考。一、Capital许可证的类型有哪些?Capital提供多种许可证类型,包括永久许可证、订阅许可证等。永久许可......
  • 【题解】Solution Set - NOIP2024集训Day32 数位 dp
    【题解】SolutionSet-NOIP2024集训Day32数位dphttps://www.becoder.com.cn/contest/5537order:1,3,5,6,2,4「SDOI2013」淘金就是要算前\(k\)大的和。考虑一个位置\((i,j)\)在变化完了之后的金子个数。(也即逆变换。设:\(f^\prime(x)\)表示在\(1\simN\)范围内,数位......
  • 【洛谷 P5730】【深基5.例10】显示屏 题解(数组+循环)
    【深基5.例10】显示屏题目描述液晶屏上,每个阿拉伯数字都是可以显示成的点阵的(其中X表示亮点,.表示暗点)。现在给出数字位数(不超过)和一串数字,要求输出这些数字在显示屏上的效果。数字的显示方式如同样例输出,注意每个数字之间都有一列间隔。输入格式第一行输入一个正整数,表示数......
  • C++Builder11的静态连接问题的解决
    1、问题用C++Builder11写了一个小程序,想将所有的运行包放在一个exe文件中,方便分发。但就是找不到原来版本中的Static-LinkC++RuntimeLibrary选项。2、经历(1)选择菜单project-options-C++linker去掉LinkwithDynamicRTL右边的√去掉>LinkwiththeDelphiRuntimeLibra......