問題への羅区P2763ソリューション

Tucaoについて:ハニーUKEこのようなものは何ですか?


トピック分析:

  1. タイトル観察面は、对于给定的组卷要求,计算满足要求的组卷方案重要である見つけることができる条件二部グラフマッチングの問題は、その後、モデリングを検討してください。

    • スーパーソース、スーパーシンクを構築し、シンクタイプに接続されたソースに接続されている質問。

    • フォーカスが上にある質問の数のタイプのモデリング。感性が、実際には、これに限ら少し意味しているかを理解するために、それぞれのタイプは量が超えることができないだけなので、多くの質問が必要なので、種類やミーティングポイントを考慮する際の質問のいくつかの種類の容量に接続されることから、フローの最大量は、タイトルをロックされる計算するとき、タイトルは表面の要件を満たすことができるようになります。(私はあなたが私が何を意味するかを理解することを願っ)QwQ \(\

    • 最後の図は、あるスーパー質問と接続されたソース、1の容量、対応するタイプと接続質問、容量1;スーパー接続シンクタイプ、タイトルの容量型番号。具体的には、スーパーソース\(S \)ノード\(1 \) ノード質問\(2-N-1 + \) ノードタイプ\(N + 2、N + K + 1 \) スーパーシンク\(T \)ノード\(N-K + 2 + \)
  2. モデリングが完了すると、記録したプログラムを検討してください。
    • 以降\(Dinic \)によってアルゴリズム\(XOR \ 1 \)前方に完了し、前縁のように、遷移エッジの側面を逆にする\(E [I] .TO \は ) 、トランスパスの終端でありますエッジに\(E [iが\; Xorの \ 1] .TO \) パスの起点であり、適切なノードを見つけるために、各側面を列挙することが可能です。
    • そしてために逆エッジの\(E [; Xorのiは\ \と、1] .V \) 場合、0に初期化される\(E [iが\; Xorの \ 1] .V \ neq0 \) 、すなわち代表この側面は、サイドも一致し、このエッジに対応し、最大流量を走っています。
    • 最後のケースは、超超ソースおよびシンクポイントを除外しました。
  3. 場合は\(Dinicが\)再びダウン走った、ANS(すなわち、最大流量)は、このデータは答えではない、まだゼロである(すなわち、出力「いいえソリューション!」)。


(詳細なメモ付き)コード:

#include<bits/stdc++.h>
#define Maxn 4010
#define Maxm 10010
#define int long long 
using namespace std;
int k,n;
inline void read(int &x)
{
    int f=1;x=0;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
    x*=f;
}
int S,T;
int ans=0,dep[Maxn];
struct edge
{
    int to,next,v;
}e[Maxm<<1];//一定注意要开两倍空间(正反两条边) 
int head[Maxn],ei=1;//一定注意这里的ei为奇数 
void add(int x,int y,int v)
{
    ei++;
    e[ei].to=y;
    e[ei].v=v;
    e[ei].next=head[x];
    head[x]=ei;
}
int bfs()
{
    queue<int>qu;
    memset(dep,0,sizeof(dep));
    dep[S]=1;
    qu.push(S);
    while(!qu.empty())
    {
        int fr=qu.front();
        qu.pop();
        for(int i=head[fr];i;i=e[i].next)
        {
            int to=e[i].to;
            if(dep[to]!=0||e[i].v==0) continue;
            qu.push(to);
            dep[to]=dep[fr]+1;
        }
    }
    return dep[T]!=0;
}
int dfs(int from,int maxflow)
{
    if(from==T) return maxflow;
    int flow=0;
    for(int i=head[from];i;i=e[i].next)
    {
        int to=e[i].to;
        if(dep[to]!=dep[from]+1||e[i].v==0) continue;
        int rst=dfs(to,min(maxflow-flow,e[i].v));
        if(rst==0) dep[to]=0;
        e[i].v-=rst;
        e[i^1].v+=rst;
        flow+=rst;
        if(flow==maxflow) break;
    }
    return flow;
}
void dinic()
{
    while(bfs())
    {
        ans+=dfs(S,LLONG_MAX);
    }
}
signed main()
{
    read(k),read(n);
    S=1,T=k+n+2;//超级源点与超级汇点 
    for(int i=1;i<=n;i++)
    {
        add(S,i+1,1);
        add(i+1,S,0);
        //超级源点与试题相连,容量为1 
    }
    for(int i=1,x;i<=k;i++)
    {
        read(x);
        add(i+n+1,T,x);
        add(T,i+n+1,0);
        //类型与超级汇点相连,容量为类型的题数 
    }
    for(int i=1,p;i<=n;i++)
    {
        read(p);
        for(int j=1,x;j<=p;j++)
        {
            read(x);
            add(i+1,x+n+1,1);
            add(x+n+1,i+1,0);
            //类型与对应的试题相连,容量为1
        }
    }
    dinic();//跑dinic 
    if(ans==0)//没有答案 
    {
        puts("No Solution!");
        return 0;
    } 
    for(int num=1;num<=k;num++)//枚举所有类型 
    {
        printf("%lld:",num);
        for(int i=2;i<=ei;i+=2)//枚举每一条边来找到相应的节点 
        {
            if(e[i].to!=S&&e[i].to!=T&&e[i^1].to!=S&&e[i^1].to!=T)//排除掉超级源点与超级汇点的情况
            {
                if(e[i^1].v!=0)//这条边已经被匹配了 
                {
                    if(e[i].to-n-1==num)//判断是否为当前类型 
                    {
                        printf("%lld ",e[i^1].to-1);
                    }
                }
            }
        }
        printf("\n");
    }
    return 0;
}

ネットワークフロー注:

  1. キーは、フロー・モデリングをネットワークにあるも、モデリングの本質です。2部グラフマッチング問題として、この質問のように私が使用方法をモデリングに撮影することができます:最大マッチング=最大流量を
  2. カウンターの元スターを初期化するとき、それは同様でなければならない奇数Eを達成するために、前方側の側面n番目、n + 1つの逆側縁は、[i]は前縁、Eは[I ^ 1]逆側であるので、前縁ことを保証する必要があります私は、すなわち、カウンタが奇数であるように初期化され、奇数です。
  3. しなければならない辺の数を前方スター2倍の領域を開くプラス側、裏面として。

おすすめ

転載: www.cnblogs.com/nth-element/p/11313897.html