「日常訓練」 Soldier and Traveling (CFR304D2E)

題意 (CodeForces 546E)

對一個無向圖,給出圖的情況與各個節點的人數/目標人數。每個節點的人只可以待在自己的城市或走到與他相鄰的節點。
問最後是否有解,輸出一可行解(我以爲是必須和答案一樣,然後本機調了半天死活不一樣,交上去結果A了- -)。

分析

典型的網絡流。問題在於建模。如何解決兩個節點的人數->目標人數?
考慮到我們始終要和這兩個狀態打交道,不妨將每個結點拆成兩個(轉移前&轉移後),這兩個點間的流量是INF。如果兩點相連(不妨設爲u,u,v,v ),那麼uvvu 分別有流量爲INF的邊。
轉移前的點連接一個源點,其間的邊流量爲它們的人數,轉移後的點連接一個匯點,邊流量同理。
建模完後跑一遍最大流就有結果了,如果匯點沒有那麼多人那麼無解,反之有解。
接下來的問題是如何求移動的人數。還記得增廣路怎麼求的嗎?(紫書p367)其中,反向邊的流量就是移動的具體數目。這樣,我們就能夠得出具體的移動方法了。
第一次寫網絡流,以後還要多加努力。

代碼

#include <bits/stdc++.h>
#define MP make_pair
#define PB push_back
#define fi first
#define se second
#define ZERO(x) memset((x), 0, sizeof(x))
#define ALL(x) (x).begin(),(x).end()
#define rep(i, a, b) for (int i = (a); i <= (b); ++i)
#define per(i, a, b) for (int i = (a); i >= (b); --i)
#define QUICKIO                  \
    ios::sync_with_stdio(false); \
    cin.tie(0);                  \
    cout.tie(0);
using namespace std;
using ll = long long;
using ull = unsigned long long;
using pi = pair<int,int>;
// 做題解

const int MAXN=1005;  
//const int MAXM=3005;  
const int INF=0x3f3f3f3f;  
struct Edge  
{  
    int from,to,cap,flow;
    Edge(int f,int t,int c,int fl):from(f),to(t),cap(c),flow(fl) {}
};

struct Dinic
{
    int n,m,s,t;
    vector<Edge> edges;
    vector<int> G[MAXN];
    void AddEdge(int _f,int _t,int _c)
    {
        edges.PB(Edge(_f,_t,_c,0));
        edges.PB(Edge(_t,_f,0,0));
        m=edges.size();
        G[_f].PB(m-2);
        G[_t].PB(m-1);
    }
    bool vis[MAXN];
    int d[MAXN],cur[MAXN];

    bool BFS()
    {
        ZERO(vis);
        queue<int> q;
        q.push(s);
        d[s]=0;
        vis[s]=true;
        while(!q.empty())
        {
            int x=q.front(); q.pop();
            rep(i,0,G[x].size()-1)
            {
                Edge& e=edges[G[x][i]];
                if(!vis[e.to] && e.cap>e.flow)
                {
                    vis[e.to]=true;
                    d[e.to]=d[x]+1;
                    q.push(e.to);
                }
            }
        }
        return vis[t];
    }

    int DFS(int x,int a)
    {
        if(x==t||a==0) return a;
        int flow=0,f;
        for(int& i=cur[x]; i<G[x].size();++i)
        {
            Edge& e=edges[G[x][i]];
            if(d[x]+1==d[e.to] && (f=DFS(e.to,min(a,e.cap-e.flow)))>0)
            {
                e.flow+=f;
                edges[G[x][i]^1].flow-=f;
                flow+=f;
                a-=f;
                if(a==0) break;
            }
        }
        return flow;
    }

    int MaxFlow(int s,int t)
    {
        this->s=s; this->t=t;
        int flow=0;
        while(BFS())
        {
            ZERO(cur);
            flow+=DFS(s,INF);
        }
        return flow;
    }
};

int main()
{
    Dinic dinic;
    int n,m;
    cin>>n>>m;
    dinic.n=2*n+2;
    //dinic.s=0; dinic.t=n+1;
    ll ta=0,tb=0;
    rep(i,1,n)
    {
        int tmp; cin>>tmp;
        dinic.AddEdge(0,i,tmp);
        ta+=tmp;
    }
    rep(i,1,n)
    {
        int tmp; cin>>tmp;
        dinic.AddEdge(i+n,2*n+1,tmp);
        tb+=tmp;
    }
    rep(i,1,n)
        dinic.AddEdge(i,i+n,INF);
    rep(i,1,m)
    {
        int a,b; cin>>a>>b;
        dinic.AddEdge(a,b+n,INF);
        dinic.AddEdge(b,a+n,INF);
    }
    int mf=dinic.MaxFlow(0,2*n+1);
    if(mf==ta && mf==tb)
    {
        cout<<"YES"<<endl;
        int f[105][105];
        ZERO(f);
        for(int i=0;i<dinic.m;i+=2)
        {
            int v=dinic.edges[i].to,u=dinic.edges[i^1].to;
            //cout<<u<<" "<<v-n<<" "<<dinic.edges[i].flow<<endl;
            if(u>=1 && u<=n)
            {
                f[u][v-n]=dinic.edges[i].flow;
            }

        }
        rep(i,1,n)
        {
            rep(j,1,n)
            {
                cout<<string(j==1 ? "" : " ")<<f[i][j]; 
            }
            cout<<endl;
        }
    }
    else cout<<"NO"<<endl;
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章